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