Bug 5596 - restart devices management improvement
[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.base.Function;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import io.netty.util.HashedWheelTimer;
17 import io.netty.util.TimerTask;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.TimeUnit;
21 import javax.annotation.Nonnull;
22 import javax.annotation.Nullable;
23 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
24 import org.opendaylight.openflowplugin.api.OFConstants;
25 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
26 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
27 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
28 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
29 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
30 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
37 import org.opendaylight.yangtools.yang.common.RpcResult;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Role context hold information about entity ownership registration,
43  * register and unregister candidate (main and tx)
44  */
45 class RoleContextImpl implements RoleContext {
46
47     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
48     // Maximum limit of timeout retries when cleaning DS, to prevent infinite recursive loops
49     private static final int MAX_CLEAN_DS_RETRIES = 3;
50
51     private SalRoleService salRoleService = null;
52     private final HashedWheelTimer hashedWheelTimer;
53     private final DeviceInfo deviceInfo;
54     private CONTEXT_STATE state;
55     private final RoleManager myManager;
56
57     RoleContextImpl(final DeviceInfo deviceInfo,
58                     final HashedWheelTimer hashedWheelTimer,
59                     final RoleManager myManager) {
60         this.deviceInfo = deviceInfo;
61         state = CONTEXT_STATE.WORKING;
62         this.myManager = myManager;
63         this.hashedWheelTimer = hashedWheelTimer;
64     }
65
66     @Nullable
67     @Override
68     public <T> RequestContext<T> createRequestContext() {
69         return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
70             @Override
71             public void close() {
72             }
73         };
74     }
75
76     @Override
77     public void setSalRoleService(@Nonnull final SalRoleService salRoleService) {
78         Preconditions.checkNotNull(salRoleService);
79         this.salRoleService = salRoleService;
80     }
81
82     @Override
83     public SalRoleService getSalRoleService() {
84         return this.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 FutureCallback<RpcResult<SetRoleOutput>>() {
109             @Override
110             public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
111                 if (LOG.isDebugEnabled()) {
112                     LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
113                 }
114             }
115
116             @Override
117             public void onFailure(final Throwable throwable) {
118                 LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
119             }
120         });
121     }
122
123     @Override
124     public ListenableFuture<Void> stopClusterServices(final boolean deviceDisconnected) {
125
126         if (!deviceDisconnected) {
127             ListenableFuture<Void> future = Futures.transform(makeDeviceSlave(), new Function<RpcResult<SetRoleOutput>, Void>() {
128                 @Nullable
129                 @Override
130                 public Void apply(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
131                     return null;
132                 }
133             });
134
135             Futures.addCallback(future, new FutureCallback<Void>() {
136                 @Override
137                 public void onSuccess(@Nullable Void aVoid) {
138                     if (LOG.isDebugEnabled()) {
139                         LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
140                     }
141                 }
142
143                 @Override
144                 public void onFailure(final Throwable throwable) {
145                     LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getLOGValue());
146                     LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
147                     myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
148
149                 }
150             });
151             return future;
152         } else {
153             return myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
154         }
155     }
156
157     @Override
158     public ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave(){
159         return sendRoleChangeToDevice(OfpRole.BECOMESLAVE);
160     }
161
162     private ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
163         LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
164         final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
165         final Short version = deviceInfo.getVersion();
166         if (null == version) {
167             LOG.debug("Device version is null");
168             return Futures.immediateFuture(null);
169         }
170         if (version < OFConstants.OFP_VERSION_1_3) {
171             LOG.debug("Device version not support ROLE");
172             return Futures.immediateFuture(null);
173         } else {
174             final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
175                     .setNode(new NodeRef(DeviceStateUtil.createNodeInstanceIdentifier(deviceInfo.getNodeId()))).build();
176             setRoleOutputFuture = getSalRoleService().setRole(setRoleInput);
177             final TimerTask timerTask = timeout -> {
178                 if (!setRoleOutputFuture.isDone()) {
179                     LOG.warn("New role {} was not propagated to device {} during 10 sec", newRole, deviceInfo.getLOGValue());
180                     setRoleOutputFuture.cancel(true);
181                 }
182             };
183             hashedWheelTimer.newTimeout(timerTask, 10, TimeUnit.SECONDS);
184         }
185         return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
186     }
187
188 }