Bug 6554 Fix rejecting connections
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / role / RoleContextImpl.java
1 /**
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.openflowplugin.impl.role;
9
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;
19
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;
44
45 /**
46  * Role context try to make change device role on device
47  */
48 class RoleContextImpl implements RoleContext {
49
50     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
51     // Maximum limit of timeout retries when cleaning DS, to prevent infinite recursive loops
52     private static final int MAX_CLEAN_DS_RETRIES = 0;
53
54     private SalRoleService salRoleService = null;
55     private final HashedWheelTimer hashedWheelTimer;
56     private final DeviceInfo deviceInfo;
57     private CONTEXT_STATE state;
58     private final RoleManager myManager;
59     private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
60     private final LifecycleService lifecycleService;
61
62     RoleContextImpl(final DeviceInfo deviceInfo,
63                     final HashedWheelTimer hashedWheelTimer,
64                     final RoleManager myManager,
65                     final LifecycleService lifecycleService) {
66         this.deviceInfo = deviceInfo;
67         state = CONTEXT_STATE.WORKING;
68         this.myManager = myManager;
69         this.hashedWheelTimer = hashedWheelTimer;
70         this.lifecycleService = lifecycleService;
71     }
72
73     @Nullable
74     @Override
75     public <T> RequestContext<T> createRequestContext() {
76         return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
77             @Override
78             public void close() {
79             }
80         };
81     }
82
83     @Override
84     public void setSalRoleService(@Nonnull final SalRoleService salRoleService) {
85         Preconditions.checkNotNull(salRoleService);
86         this.salRoleService = salRoleService;
87     }
88
89     @Override
90     public CONTEXT_STATE getState() {
91         return this.state;
92     }
93
94     @Override
95     public void setState(CONTEXT_STATE state) {
96         this.state = state;
97     }
98
99     @Override
100     public ServiceGroupIdentifier getServiceIdentifier() {
101         return this.deviceInfo.getServiceIdentifier();
102     }
103
104     @Override
105     public DeviceInfo getDeviceInfo() {
106         return this.deviceInfo;
107     }
108
109     public void startupClusterServices() throws ExecutionException, InterruptedException {
110         Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
111             @Override
112             public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
113                 if (LOG.isDebugEnabled()) {
114                     LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
115                 }
116             }
117
118             @Override
119             public void onFailure(final Throwable throwable) {
120                 LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
121                 lifecycleService.closeConnection();
122             }
123         });
124     }
125
126     @Override
127     public ListenableFuture<Void> stopClusterServices(final boolean deviceDisconnected) {
128
129         if (!deviceDisconnected) {
130             ListenableFuture<Void> future = Futures.transform(makeDeviceSlave(), new Function<RpcResult<SetRoleOutput>, Void>() {
131                 @Nullable
132                 @Override
133                 public Void apply(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
134                     return null;
135                 }
136             });
137
138             Futures.addCallback(future, new FutureCallback<Void>() {
139                 @Override
140                 public void onSuccess(@Nullable Void aVoid) {
141                     if (LOG.isDebugEnabled()) {
142                         LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
143                     }
144                 }
145
146                 @Override
147                 public void onFailure(final Throwable throwable) {
148                     LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getLOGValue());
149                     LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
150                     myManager.removeDeviceFromOperationalDS(deviceInfo);
151                 }
152             });
153             return future;
154         } else {
155             return myManager.removeDeviceFromOperationalDS(deviceInfo);
156         }
157     }
158
159     @Override
160     public ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave(){
161         return sendRoleChangeToDevice(OfpRole.BECOMESLAVE);
162     }
163
164     @VisibleForTesting
165     ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
166         if (LOG.isDebugEnabled()) {
167             LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
168         }
169         final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
170         if (deviceInfo.getVersion() >= OFConstants.OFP_VERSION_1_3) {
171             final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
172                     .setNode(new NodeRef(deviceInfo.getNodeInstanceIdentifier())).build();
173             setRoleOutputFuture = this.salRoleService.setRole(setRoleInput);
174             final TimerTask timerTask = timeout -> {
175                 if (!setRoleOutputFuture.isDone()) {
176                     LOG.warn("New role {} was not propagated to device {} during 5 sec", newRole, deviceInfo.getLOGValue());
177                     setRoleOutputFuture.cancel(true);
178                 }
179             };
180             hashedWheelTimer.newTimeout(timerTask, 5, TimeUnit.SECONDS);
181         } else {
182             LOG.info("Device: {} with version: {} does not support role", deviceInfo.getLOGValue(), deviceInfo.getVersion());
183             return Futures.immediateFuture(null);
184         }
185         return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
186     }
187
188     @Override
189     public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
190         this.clusterInitializationPhaseHandler = handler;
191     }
192
193     @Override
194     public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
195
196         if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
197             LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
198             return false;
199         }
200
201         Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
202             @Override
203             public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
204                 if (LOG.isDebugEnabled()) {
205                     LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
206                 }
207             }
208
209             @Override
210             public void onFailure(final Throwable throwable) {
211                 LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
212                 lifecycleService.closeConnection();
213             }
214         });
215
216         return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
217     }
218 }