Convert to mdsal EntityOwnershipService APIs
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepSouthboundProvider.java
1 /*
2  * Copyright © 2015, 2017 Ericsson India Global Services Pvt Ltd. 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.ovsdb.hwvtepsouthbound;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.CheckedFuture;
12 import java.util.Collection;
13 import java.util.concurrent.ExecutionException;
14 import java.util.concurrent.atomic.AtomicBoolean;
15 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
23 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
24 import org.opendaylight.mdsal.eos.binding.api.Entity;
25 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
26 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
27 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListener;
28 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
29 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
30 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
31 import org.opendaylight.ovsdb.hwvtepsouthbound.reconciliation.configuration.HwvtepReconciliationManager;
32 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvoker;
33 import org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl;
34 import org.opendaylight.ovsdb.lib.OvsdbConnection;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
37 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 public class HwvtepSouthboundProvider implements ClusteredDataTreeChangeListener<Topology>, AutoCloseable {
45
46     private static final Logger LOG = LoggerFactory.getLogger(HwvtepSouthboundProvider.class);
47     private static final String ENTITY_TYPE = "ovsdb-hwvtepsouthbound-provider";
48
49     private final DataBroker dataBroker;
50     private final EntityOwnershipService entityOwnershipService;
51     private final OvsdbConnection ovsdbConnection;
52
53     private HwvtepConnectionManager cm;
54     private TransactionInvoker txInvoker;
55     private EntityOwnershipCandidateRegistration registration;
56     private HwvtepsbPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
57     private HwvtepDataChangeListener hwvtepDTListener;
58     private HwvtepReconciliationManager hwvtepReconciliationManager;
59     private final AtomicBoolean registered = new AtomicBoolean(false);
60     private ListenerRegistration<HwvtepSouthboundProvider> operTopologyRegistration;
61
62     public HwvtepSouthboundProvider(final DataBroker dataBroker,
63             final EntityOwnershipService entityOwnershipServiceDependency,
64             final OvsdbConnection ovsdbConnection,
65             final DOMSchemaService schemaService,
66             final BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
67         this.dataBroker = dataBroker;
68         this.entityOwnershipService = entityOwnershipServiceDependency;
69         registration = null;
70         this.ovsdbConnection = ovsdbConnection;
71         HwvtepSouthboundUtil.setInstanceIdentifierCodec(new InstanceIdentifierCodec(schemaService,
72                 bindingNormalizedNodeSerializer));
73         LOG.info("HwvtepSouthboundProvider ovsdbConnectionService: {}", ovsdbConnection);
74     }
75
76     /**
77      * Used by blueprint when starting the container.
78      */
79     public void init() {
80         LOG.info("HwvtepSouthboundProvider Session Initiated");
81         txInvoker = new TransactionInvokerImpl(dataBroker);
82         cm = new HwvtepConnectionManager(dataBroker, txInvoker, entityOwnershipService);
83         hwvtepDTListener = new HwvtepDataChangeListener(dataBroker, cm);
84         hwvtepReconciliationManager = new HwvtepReconciliationManager(dataBroker, cm);
85         //Register listener for entityOnwership changes
86         providerOwnershipChangeListener =
87                 new HwvtepsbPluginInstanceEntityOwnershipListener(this,this.entityOwnershipService);
88
89         //register instance entity to get the ownership of the provider
90         Entity instanceEntity = new Entity(ENTITY_TYPE, ENTITY_TYPE);
91         try {
92             registration = entityOwnershipService.registerCandidate(instanceEntity);
93         } catch (CandidateAlreadyRegisteredException e) {
94             LOG.warn("HWVTEP Southbound Provider instance entity {} was already "
95                     + "registered for ownership", instanceEntity, e);
96         }
97         InstanceIdentifier<Topology> path = InstanceIdentifier
98                 .create(NetworkTopology.class)
99                 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
100         DataTreeIdentifier<Topology> treeId =
101                 new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, path);
102
103         LOG.trace("Registering listener for path {}", treeId);
104         operTopologyRegistration = dataBroker.registerDataTreeChangeListener(treeId, this);
105     }
106
107     @Override
108     @SuppressWarnings("checkstyle:IllegalCatch")
109     public void close() throws Exception {
110         LOG.info("HwvtepSouthboundProvider Closed");
111         if (txInvoker != null) {
112             try {
113                 txInvoker.close();
114                 txInvoker = null;
115             } catch (Exception e) {
116                 LOG.error("HWVTEP Southbound Provider failed to close TransactionInvoker", e);
117             }
118         }
119         if (cm != null) {
120             cm.close();
121             cm = null;
122         }
123         if (registration != null) {
124             registration.close();
125             registration = null;
126         }
127         if (providerOwnershipChangeListener != null) {
128             providerOwnershipChangeListener.close();
129             providerOwnershipChangeListener = null;
130         }
131         if (hwvtepDTListener != null) {
132             hwvtepDTListener.close();
133             hwvtepDTListener = null;
134         }
135         if (operTopologyRegistration != null) {
136             operTopologyRegistration.close();
137             operTopologyRegistration = null;
138         }
139     }
140
141     private void initializeHwvtepTopology(LogicalDatastoreType type) {
142         InstanceIdentifier<Topology> path = InstanceIdentifier
143                 .create(NetworkTopology.class)
144                 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID));
145         ReadWriteTransaction transaction = dataBroker.newReadWriteTransaction();
146         CheckedFuture<Optional<Topology>, ReadFailedException> hwvtepTp = transaction.read(type, path);
147         try {
148             if (!hwvtepTp.get().isPresent()) {
149                 TopologyBuilder tpb = new TopologyBuilder();
150                 tpb.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
151                 transaction.put(type, path, tpb.build(), true);
152                 transaction.submit();
153             } else {
154                 transaction.cancel();
155             }
156         } catch (InterruptedException | ExecutionException e) {
157             LOG.error("Error initializing hwvtep topology", e);
158         }
159     }
160
161     public void handleOwnershipChange(EntityOwnershipChange ownershipChange) {
162         if (ownershipChange.getState().isOwner()) {
163             LOG.info("*This* instance of HWVTEP southbound provider is set as a MASTER instance");
164             LOG.info("Initialize HWVTEP topology {} in operational and config data store if not already present",
165                     HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID);
166             initializeHwvtepTopology(LogicalDatastoreType.OPERATIONAL);
167             initializeHwvtepTopology(LogicalDatastoreType.CONFIGURATION);
168         } else {
169             LOG.info("*This* instance of HWVTEP southbound provider is set as a SLAVE instance");
170         }
171     }
172
173
174     @Override
175     public void onDataTreeChanged(Collection<DataTreeModification<Topology>> collection) {
176         if (!registered.getAndSet(true)) {
177             LOG.info("Starting the ovsdb port");
178             ovsdbConnection.registerConnectionListener(cm);
179             ovsdbConnection.startOvsdbManager();
180         }
181         //mdsal registration/deregistration in mdsal update callback should be avoided
182         new Thread(() -> {
183             if (operTopologyRegistration != null) {
184                 operTopologyRegistration.close();
185                 operTopologyRegistration = null;
186             }
187         }).start();
188     }
189
190     private static class HwvtepsbPluginInstanceEntityOwnershipListener implements EntityOwnershipListener {
191         private final HwvtepSouthboundProvider hsp;
192         private final EntityOwnershipListenerRegistration listenerRegistration;
193
194         HwvtepsbPluginInstanceEntityOwnershipListener(HwvtepSouthboundProvider hsp,
195                 EntityOwnershipService entityOwnershipService) {
196             this.hsp = hsp;
197             listenerRegistration = entityOwnershipService.registerListener(ENTITY_TYPE, this);
198         }
199
200         public void close() {
201             this.listenerRegistration.close();
202         }
203
204         @Override
205         public void ownershipChanged(EntityOwnershipChange ownershipChange) {
206             hsp.handleOwnershipChange(ownershipChange);
207         }
208     }
209
210     public HwvtepConnectionManager getHwvtepConnectionManager() {
211         return cm;
212     }
213 }