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