483b8c7fafbbc219395c875c46f4c09fcfbb8851
[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.lifecycle.LifecycleService;
28 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
29 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
30 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
31 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
38 import org.opendaylight.yangtools.yang.common.RpcResult;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * Role context hold information about entity ownership registration,
44  * register and unregister candidate (main and tx)
45  */
46 class RoleContextImpl implements RoleContext {
47
48     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
49     // Maximum limit of timeout retries when cleaning DS, to prevent infinite recursive loops
50     private static final int MAX_CLEAN_DS_RETRIES = 3;
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 final LifecycleService lifecycleService;
58
59     RoleContextImpl(final DeviceInfo deviceInfo,
60                     final HashedWheelTimer hashedWheelTimer,
61                     final RoleManager myManager,
62                     final LifecycleService lifecycleService) {
63         this.deviceInfo = deviceInfo;
64         this.lifecycleService = lifecycleService;
65         state = CONTEXT_STATE.WORKING;
66         this.myManager = myManager;
67         this.hashedWheelTimer = hashedWheelTimer;
68     }
69
70     @Nullable
71     @Override
72     public <T> RequestContext<T> createRequestContext() {
73         return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
74             @Override
75             public void close() {
76             }
77         };
78     }
79
80     @Override
81     public void setSalRoleService(@Nonnull final SalRoleService salRoleService) {
82         Preconditions.checkNotNull(salRoleService);
83         this.salRoleService = salRoleService;
84     }
85
86     @Override
87     public SalRoleService getSalRoleService() {
88         return this.salRoleService;
89     }
90
91     @Override
92     public CONTEXT_STATE getState() {
93         return this.state;
94     }
95
96     @Override
97     public void setState(CONTEXT_STATE state) {
98         this.state = state;
99     }
100
101     @Override
102     public ServiceGroupIdentifier getServiceIdentifier() {
103         return this.deviceInfo.getServiceIdentifier();
104     }
105
106     @Override
107     public DeviceInfo getDeviceInfo() {
108         return this.deviceInfo;
109     }
110
111     public void startupClusterServices() throws ExecutionException, InterruptedException {
112         Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
113             @Override
114             public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
115                 if (LOG.isDebugEnabled()) {
116                     LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getNodeId().getValue());
117                 }
118             }
119
120             @Override
121             public void onFailure(final Throwable throwable) {
122                 LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getNodeId().getValue());
123                 lifecycleService.closeConnection();
124             }
125         });
126     }
127
128     @Override
129     public ListenableFuture<Void> stopClusterServices() {
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.getNodeId().getValue());
143                         }
144                         myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
145                     }
146
147                     @Override
148                     public void onFailure(final Throwable throwable) {
149                         LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getNodeId().getValue());
150                         LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
151                         myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
152
153                     }
154                 });
155         return future;
156     }
157
158     @Override
159     public ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave(){
160         return sendRoleChangeToDevice(OfpRole.BECOMESLAVE);
161     }
162
163     private ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
164         LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
165         final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
166         final Short version = deviceInfo.getVersion();
167         if (null == version) {
168             LOG.debug("Device version is null");
169             return Futures.immediateFuture(null);
170         }
171         if (version < OFConstants.OFP_VERSION_1_3) {
172             LOG.debug("Device version not support ROLE");
173             return Futures.immediateFuture(null);
174         } else {
175             final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
176                     .setNode(new NodeRef(DeviceStateUtil.createNodeInstanceIdentifier(deviceInfo.getNodeId()))).build();
177             setRoleOutputFuture = getSalRoleService().setRole(setRoleInput);
178             final TimerTask timerTask = timeout -> {
179                 if (!setRoleOutputFuture.isDone()) {
180                     LOG.warn("New role {} was not propagated to device {} during 10 sec", newRole, deviceInfo.getNodeId());
181                     setRoleOutputFuture.cancel(true);
182                 }
183             };
184             hashedWheelTimer.newTimeout(timerTask, 10, TimeUnit.SECONDS);
185         }
186         return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
187     }
188
189 }