Merge "Bug 5596 Cleaning lifecycle conductor"
[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.Preconditions;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.JdkFutureAdapters;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import io.netty.util.HashedWheelTimer;
15 import io.netty.util.TimerTask;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import java.util.concurrent.TimeUnit;
19 import javax.annotation.Nonnull;
20 import javax.annotation.Nullable;
21 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
22 import org.opendaylight.openflowplugin.api.OFConstants;
23 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
24 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
25 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
26 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
27 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
28 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
35 import org.opendaylight.yangtools.yang.common.RpcResult;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * Role context hold information about entity ownership registration,
41  * register and unregister candidate (main and tx)
42  */
43 class RoleContextImpl implements RoleContext {
44
45     private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
46     // Maximum limit of timeout retries when cleaning DS, to prevent infinite recursive loops
47     private static final int MAX_CLEAN_DS_RETRIES = 3;
48
49     private SalRoleService salRoleService = null;
50     private final HashedWheelTimer hashedWheelTimer;
51     private final DeviceInfo deviceInfo;
52     private CONTEXT_STATE state;
53     private final RoleManager myManager;
54
55     RoleContextImpl(final DeviceInfo deviceInfo,
56                     final HashedWheelTimer hashedWheelTimer,
57                     final RoleManager myManager) {
58         this.deviceInfo = deviceInfo;
59         state = CONTEXT_STATE.WORKING;
60         this.myManager = myManager;
61         this.hashedWheelTimer = hashedWheelTimer;
62     }
63
64     @Nullable
65     @Override
66     public <T> RequestContext<T> createRequestContext() {
67         return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
68             @Override
69             public void close() {
70             }
71         };
72     }
73
74     @Override
75     public void setSalRoleService(@Nonnull final SalRoleService salRoleService) {
76         Preconditions.checkNotNull(salRoleService);
77         this.salRoleService = salRoleService;
78     }
79
80     @Override
81     public SalRoleService getSalRoleService() {
82         return this.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         //TODO: Add callback ?
107         sendRoleChangeToDevice(OfpRole.BECOMEMASTER).get();
108     }
109
110     @Override
111     public ListenableFuture<Void> stopClusterServices() {
112         ListenableFuture<Void> future;
113         try {
114             //TODO: Add callback
115             sendRoleChangeToDevice(OfpRole.BECOMESLAVE).get();
116         } catch (InterruptedException | ExecutionException e) {
117             LOG.warn("Send role to device failed ", e);
118         } finally {
119             myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
120             future = Futures.immediateFuture(null);
121         }
122         return future;
123     }
124
125     private ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
126         LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
127         final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
128         final Short version = deviceInfo.getVersion();
129         if (null == version) {
130             LOG.debug("Device version is null");
131             return Futures.immediateFuture(null);
132         }
133         if (version < OFConstants.OFP_VERSION_1_3) {
134             LOG.debug("Device version not support ROLE");
135             return Futures.immediateFuture(null);
136         } else {
137             final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
138                     .setNode(new NodeRef(DeviceStateUtil.createNodeInstanceIdentifier(deviceInfo.getNodeId()))).build();
139             setRoleOutputFuture = getSalRoleService().setRole(setRoleInput);
140             final TimerTask timerTask = timeout -> {
141                 if (!setRoleOutputFuture.isDone()) {
142                     LOG.warn("New role {} was not propagated to device {} during 10 sec", newRole, deviceInfo.getNodeId());
143                     setRoleOutputFuture.cancel(true);
144                 }
145             };
146             hashedWheelTimer.newTimeout(timerTask, 10, TimeUnit.SECONDS);
147         }
148         return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
149     }
150
151 }