BUG-5685: Register BGP Application Peer Cluster Singleton Service 24/44124/1
authorClaudio D. Gasparini <cgaspari@cisco.com>
Wed, 10 Aug 2016 12:53:28 +0000 (14:53 +0200)
committerMilos Fabian <milfabia@cisco.com>
Wed, 17 Aug 2016 07:10:43 +0000 (07:10 +0000)
Register BGP Application Peer Cluster Singleton Service.
When running on clustering, it was need it to have different
configuration per instance to avoid conflicts.
Now all instance can have same configuration,
since cluster service provider take cares of make active
the one is running on Leader Cluster. If Leader goes down,
the instance from the new Leader will become active.

Change-Id: I5316a50b5ceaf54c838018860baefc5ae326465b
Signed-off-by: Claudio D. Gasparini <cgaspari@cisco.com>
(cherry picked from commit 0aabee8976574d2765248f134d4292e345adcb83)

bgp/rib-impl/src/main/java/org/opendaylight/controller/config/yang/bgp/rib/impl/BGPApplicationPeerModule.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/ApplicationPeer.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/config/AppPeer.java
bgp/rib-impl/src/test/java/org/opendaylight/protocol/bgp/rib/impl/PeerTest.java

index 2a8fc0621878062a1e7197ca1d0219331cd068e5..13bc8b99d68f1f690f7f827f750d0d14653304f6 100755 (executable)
@@ -19,6 +19,7 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.re
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.ProtocolKey;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.policy.types.rev151009.BGP;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.osgi.framework.BundleContext;
 
@@ -46,20 +47,19 @@ public class BGPApplicationPeerModule extends org.opendaylight.controller.config
     @Override
     public java.lang.AutoCloseable createInstance() {
         final RIB rib = getTargetRibDependency();
-        final WaitingServiceTracker<BgpDeployer> bgpDeployerTracker =
-                WaitingServiceTracker.create(BgpDeployer.class, this.bundleContext);
+        final WaitingServiceTracker<BgpDeployer> bgpDeployerTracker = WaitingServiceTracker.create(BgpDeployer.class, this.bundleContext);
         final BgpDeployer bgpDeployer = bgpDeployerTracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
         //map configuration to OpenConfig BGP
         final Neighbor neighbor = bgpDeployer.getMappingService().fromApplicationPeer(getApplicationRibId(), getBgpPeerId());
         //write to configuration DS
-        final KeyedInstanceIdentifier<Neighbor, NeighborKey> neighborIId = bgpDeployer.getInstanceIdentifier().child(Protocols.class).child(Protocol.class,
-                new ProtocolKey(BGP.class, rib.getInstanceIdentifier().getKey().getId().getValue()))
-                .augmentation(Protocol1.class).child(Bgp.class).child(Neighbors.class).child(Neighbor.class, neighbor.getKey());
-        bgpDeployer.writeConfiguration(neighbor, neighborIId);
+        final KeyedInstanceIdentifier<Protocol, ProtocolKey> protocolIId = bgpDeployer.getInstanceIdentifier().child(Protocols.class)
+            .child(Protocol.class, new ProtocolKey(BGP.class, rib.getInstanceIdentifier().getKey().getId().getValue()));
+        final InstanceIdentifier<Bgp> bgpIID = protocolIId.augmentation(Protocol1.class).child(Bgp.class);
+        final KeyedInstanceIdentifier<Neighbor, NeighborKey> neighborIId = protocolIId.augmentation(Protocol1.class).child(Bgp.class)
+            .child(Neighbors.class).child(Neighbor.class, neighbor.getKey());
+        bgpDeployer.onNeighborModified(bgpIID, neighbor, () -> bgpDeployer.writeConfiguration(neighbor, neighborIId));
 
-        return () -> {
-            bgpDeployerTracker.close();
-        };
+        return bgpDeployerTracker::close;
     }
 
     public void setBundleContext(final BundleContext bundleContext) {
index deca1178d4ae6511ee373ee3311ee188bcecb8bc..b064be877fa3e375487fe9bd8cc50fd6b2baa375 100644 (file)
@@ -61,38 +61,46 @@ public class ApplicationPeer implements AutoCloseable, org.opendaylight.protocol
     private final byte[] rawIdentifier;
     private final String name;
     private final YangInstanceIdentifier adjRibsInId;
-    private final DOMTransactionChain chain;
-    private final DOMTransactionChain writerChain;
+    private final Ipv4Address ipAddress;
     private final BGPConfigModuleTracker moduleTracker;
-    private final EffectiveRibInWriter effectiveRibInWriter;
+    private final RIB rib;
+    private final YangInstanceIdentifier peerIId;
+    private DOMTransactionChain chain;
+    private DOMTransactionChain writerChain;
+    private EffectiveRibInWriter effectiveRibInWriter;
     private AdjRibInWriter writer;
 
     public ApplicationPeer(final ApplicationRibId applicationRibId, final Ipv4Address ipAddress, final RIB rib,
-            final BGPConfigModuleTracker moduleTracker) {
-        this.name = applicationRibId.getValue().toString();
+        final BGPConfigModuleTracker moduleTracker) {
+        this.name = applicationRibId.getValue();
         final RIB targetRib = Preconditions.checkNotNull(rib);
         this.rawIdentifier = InetAddresses.forString(ipAddress.getValue()).getAddress();
         final NodeIdentifierWithPredicates peerId = IdentifierUtils.domPeerId(RouterIds.createPeerId(ipAddress));
-        final YangInstanceIdentifier peerIId = targetRib.getYangRibId().node(Peer.QNAME).node(peerId);
-        this.adjRibsInId = peerIId.node(AdjRibIn.QNAME).node(Tables.QNAME);
-        this.chain = targetRib.createPeerChain(this);
-        this.writerChain = targetRib.createPeerChain(this);
-        this.writer = AdjRibInWriter.create(targetRib.getYangRibId(), PeerRole.Internal, Optional.of(SimpleRoutingPolicy.AnnounceNone), this.writerChain);
-        this.writer = this.writer.transform(RouterIds.createPeerId(ipAddress), targetRib.getRibSupportContext(), targetRib.getLocalTablesKeys(),
-            Collections.emptyList());
-        //TODO need to create effective rib in writer with route counter here
-        this.effectiveRibInWriter = EffectiveRibInWriter.create(targetRib.getService(), targetRib.createPeerChain(this), peerIId,
-            targetRib.getImportPolicyPeerTracker(), targetRib.getRibSupportContext(), PeerRole.Internal);
+        this.peerIId = targetRib.getYangRibId().node(Peer.QNAME).node(peerId);
+        this.adjRibsInId = this.peerIId.node(AdjRibIn.QNAME).node(Tables.QNAME);
+        this.rib = targetRib;
+        this.ipAddress = ipAddress;
         this.moduleTracker = moduleTracker;
-        if (moduleTracker != null) {
-            moduleTracker.onInstanceCreate();
-        }
     }
 
     public ApplicationPeer(final ApplicationRibId applicationRibId, final Ipv4Address bgpPeerId, final RIB targetRibDependency) {
         this(applicationRibId, bgpPeerId, targetRibDependency, null);
     }
 
+    public void instantiateServiceInstance() {
+        this.chain = this.rib.createPeerChain(this);
+        this.writerChain = this.rib.createPeerChain(this);
+        this.writer = AdjRibInWriter.create(this.rib.getYangRibId(), PeerRole.Internal, Optional.of(SimpleRoutingPolicy.AnnounceNone), this.writerChain);
+        this.writer = this.writer.transform(RouterIds.createPeerId(this.ipAddress), this.rib.getRibSupportContext(), this.rib.getLocalTablesKeys(),
+            Collections.emptyList());
+        //TODO need to create effective rib in writer with route counter here
+        this.effectiveRibInWriter = EffectiveRibInWriter.create(this.rib.getService(), this.rib.createPeerChain(this), this.peerIId,
+            this.rib.getImportPolicyPeerTracker(), this.rib.getRibSupportContext(), PeerRole.Internal);
+        if (moduleTracker != null) {
+            moduleTracker.onInstanceCreate();
+        }
+    }
+
     /**
      * Routes come from application RIB that is identified by (configurable) name.
      * Each route is pushed into AdjRibsInWriter with it's whole context. In this
index 6ec0f1995cebd9d11f18ea624d278681aab929cc..7527a41cdf357bbd6d0dbab1bb2c8066c4155f72 100644 (file)
@@ -10,38 +10,40 @@ package org.opendaylight.protocol.bgp.rib.impl.config;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
+import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
 import org.opendaylight.protocol.bgp.rib.impl.ApplicationPeer;
 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer.WriteConfiguration;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Config;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.ApplicationRibId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.Tables;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class AppPeer implements PeerBean {
-
+    private static final Logger LOG = LoggerFactory.getLogger(AppPeer.class);
     private static final QName APP_ID_QNAME = QName.create(ApplicationRib.QNAME, "id").intern();
-
-    private ApplicationPeer applicationPeer;
-    private ListenerRegistration<ApplicationPeer> registration;
     private Neighbor currentConfiguration;
+    private BgpAppPeerSingletonService bgpAppPeerSingletonService;
 
     @Override
     public void start(final RIB rib, final Neighbor neighbor, final BGPOpenConfigMappingService mappingService, final WriteConfiguration configurationWriter) {
-        this.currentConfiguration = Preconditions.checkNotNull(neighbor);
-        final ApplicationRibId appRibId = createAppRibId(neighbor);
-        this.applicationPeer = new ApplicationPeer(appRibId, neighbor.getNeighborAddress().getIpv4Address(), rib);
-        final YangInstanceIdentifier yangIId = YangInstanceIdentifier.builder().node(ApplicationRib.QNAME)
-                .nodeWithKey(ApplicationRib.QNAME, APP_ID_QNAME, appRibId.getValue()).node(Tables.QNAME).node(Tables.QNAME).build();
-        this.registration = rib.getService().registerDataTreeChangeListener(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, yangIId),
-                this.applicationPeer);
+        this.currentConfiguration = neighbor;
+        this.bgpAppPeerSingletonService = new BgpAppPeerSingletonService(rib, createAppRibId(neighbor), neighbor.getNeighborAddress().getIpv4Address());
     }
 
     @Override
@@ -52,9 +54,10 @@ public class AppPeer implements PeerBean {
 
     @Override
     public void close() {
-        if (this.applicationPeer != null) {
-            this.registration.close();
-            this.applicationPeer.close();
+        try {
+            this.bgpAppPeerSingletonService.close();
+        } catch (final Exception e) {
+            LOG.warn("Failed to close application peer instance", e);
         }
     }
 
@@ -71,4 +74,52 @@ public class AppPeer implements PeerBean {
         return new ApplicationRibId(neighbor.getNeighborAddress().getIpv4Address().getValue());
     }
 
-}
+    private final class BgpAppPeerSingletonService implements ClusterSingletonService, AutoCloseable {
+        private final ApplicationPeer applicationPeer;
+        private final DOMDataTreeChangeService dataTreeChangeService;
+        private final ApplicationRibId appRibId;
+        private ClusterSingletonServiceRegistration singletonServiceRegistration;
+        private ListenerRegistration<ApplicationPeer> registration;
+        private final ServiceGroupIdentifier serviceGroupIdentifier;
+
+        BgpAppPeerSingletonService(final RIB rib, final ApplicationRibId appRibId, final Ipv4Address neighborAddress) {
+            this.applicationPeer = new ApplicationPeer(appRibId, neighborAddress, rib);
+            this.appRibId = appRibId;
+            this.dataTreeChangeService = rib.getService();
+            this.serviceGroupIdentifier = rib.getRibIServiceGroupIdentifier();
+            LOG.info("Application Peer Singleton Service {} registered", getIdentifier());
+            this.singletonServiceRegistration = rib.registerClusterSingletonService(this);
+        }
+
+        @Override
+        public void close() throws Exception {
+            if (this.singletonServiceRegistration != null) {
+                this.singletonServiceRegistration.close();
+                this.singletonServiceRegistration = null;
+            }
+        }
+
+        @Override
+        public void instantiateServiceInstance() {
+            LOG.info("Application Peer Singleton Service {} instantiated", getIdentifier());
+            final YangInstanceIdentifier yangIId = YangInstanceIdentifier.builder().node(ApplicationRib.QNAME)
+                .nodeWithKey(ApplicationRib.QNAME, APP_ID_QNAME, appRibId.getValue()).node(Tables.QNAME).node(Tables.QNAME).build();
+            this.applicationPeer.instantiateServiceInstance();
+            this.registration = this.dataTreeChangeService
+                .registerDataTreeChangeListener(new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, yangIId), this.applicationPeer);
+        }
+
+        @Override
+        public ListenableFuture<Void> closeServiceInstance() {
+            LOG.info("Application Peer Singleton Service {} instance closed", getIdentifier());
+            this.registration.close();
+            this.applicationPeer.close();
+            return Futures.immediateFuture(null);
+        }
+
+        @Override
+        public ServiceGroupIdentifier getIdentifier() {
+            return this.serviceGroupIdentifier;
+        }
+    }
+}
\ No newline at end of file
index 88e10dab90d372c3e4bfd0f0d26f9b28756e778b..fa74d4557ebcc39fc70b92c082714559aeff3a64 100644 (file)
@@ -127,6 +127,7 @@ public class PeerTest extends AbstractRIBTestSetup {
         final Ipv4Prefix second = new Ipv4Prefix("127.0.0.1/32");
         final Ipv4Prefix third = new Ipv4Prefix("127.0.0.3/32");
         this.peer = new ApplicationPeer(new ApplicationRibId("t"), new Ipv4Address("127.0.0.1"), getRib());
+        this.peer.instantiateServiceInstance();
         final YangInstanceIdentifier base = getRib().getYangRibId().node(LocRib.QNAME).node(Tables.QNAME).node(RibSupportUtils.toYangTablesKey(KEY));
         this.peer.onDataTreeChanged(ipv4Input(base, ModificationType.WRITE, first, second, third));
         assertEquals(3, this.routes.size());