Clustering - common infrastructure. 44/40444/17
authorJozef Gloncak <jgloncak@cisco.com>
Thu, 16 Jun 2016 13:42:45 +0000 (15:42 +0200)
committerLorand Jakab <lojakab@cisco.com>
Thu, 21 Jul 2016 18:19:13 +0000 (13:19 -0500)
Common class for clustering operations for each module.

Change-Id: If401eba45155e07846f025340b6499969213e7bb
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
features/pom.xml
features/src/main/features/features.xml
mappingservice/clustering/pom.xml [new file with mode: 0644]
mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImpl.java [new file with mode: 0644]
mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/api/ClusterNodeModuleSwitcher.java [new file with mode: 0644]
mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/util/ClusteringUtil.java [new file with mode: 0644]
mappingservice/clustering/src/main/test/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImplTest.java [new file with mode: 0644]
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/mdsal/AbstractDataListener.java
mappingservice/pom.xml
mappingservice/southbound/src/main/java/org/opendaylight/lispflowmapping/southbound/lisp/AuthenticationKeyDataListener.java

index 9b7afcf710156e51e4eae1f72a0876dbd825063a..f0a31d5acf4270fd4b9ca919a3fbf87966e0a005 100644 (file)
@@ -89,6 +89,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mappingservice.clustering</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>mappingservice.dsbackend</artifactId>
index 314fc6e78bdecbd66783e096da604837e051bb72..0cfbbfde1aec864b13420698b881cfebabfe02ce 100644 (file)
@@ -31,6 +31,7 @@
         <feature version="${mdsal.version}">odl-mdsal-broker</feature>
         <feature version='${project.version}'>odl-lispflowmapping-models</feature>
         <feature version="${project.version}">odl-lispflowmapping-inmemorydb</feature>
+        <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.clustering/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.dsbackend/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.mapcache/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.implementation/{{VERSION}}</bundle>
@@ -52,6 +53,7 @@
         <feature version="${mdsal.version}">odl-mdsal-broker</feature>
         <feature version='${project.version}'>odl-lispflowmapping-models</feature>
         <feature version="${project.version}">odl-lispflowmapping-inmemorydb</feature>
+        <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.clustering/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.dsbackend/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.mapcache/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.lispflowmapping/mappingservice.southbound/{{VERSION}}</bundle>
diff --git a/mappingservice/clustering/pom.xml b/mappingservice/clustering/pom.xml
new file mode 100644 (file)
index 0000000..4ebfe9c
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.lispflowmapping</groupId>
+    <artifactId>mappingservice-parent</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>mappingservice.clustering</artifactId>
+  <packaging>bundle</packaging>
+  <name>Mapping Service Clustering (mappingservice.clustering)</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-api</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <!-- Enforce odlparent checkstyle -->
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-checkstyle-plugin</artifactId>
+          <configuration>
+            <includeTestSourceDirectory>true</includeTestSourceDirectory>
+            <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <!--
+      Maven Site Configuration
+
+      The following configuration is necessary for maven-site-plugin to
+      correctly identify the correct deployment path for OpenDaylight Maven
+      sites.
+  -->
+  <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+  <distributionManagement>
+    <site>
+      <id>opendaylight-site</id>
+      <url>${nexus.site.url}/${project.artifactId}/</url>
+    </site>
+  </distributionManagement>
+</project>
diff --git a/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImpl.java b/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImpl.java
new file mode 100644 (file)
index 0000000..c3b8068
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.lispflowmapping.clustering;
+
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_NAME;
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_TYPE;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.lispflowmapping.clustering.api.ClusterNodeModuleSwitcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class responsible for turning on|off module in node cluster.
+ */
+public class ClusterNodeModulSwitcherImpl implements EntityOwnershipListener  {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClusterNodeModulSwitcherImpl.class);
+    private final EntityOwnershipService entityOwnershipService;
+    private final Entity entity;
+    private boolean moduleIsRunning = true;
+    private ClusterNodeModuleSwitcher module;
+
+    public ClusterNodeModulSwitcherImpl(final EntityOwnershipService entityOwnershipService) {
+        this.entityOwnershipService = entityOwnershipService;
+        this.entityOwnershipService.registerListener(LISPFLOWMAPPING_ENTITY_NAME, this);
+        entity = new Entity(LISPFLOWMAPPING_ENTITY_NAME, LISPFLOWMAPPING_ENTITY_TYPE);
+        try {
+            this.entityOwnershipService.registerCandidate(entity);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.debug("Candidate already registered. Trace: {}", e);
+        }
+    }
+
+    @Override
+    public void ownershipChanged(final EntityOwnershipChange entityOwnershipChange) {
+        LOG.debug("Entity ownership change message received.");
+        switchModuleState(entityOwnershipChange.isOwner());
+    }
+
+    public void switchModuleByEntityOwnership() {
+        switchModuleState(isMaster());
+    }
+
+    private void switchModuleState(final boolean isOwner) {
+        if (module != null) {
+            if (!isOwner && moduleIsRunning) {
+                module.stopModule();
+                moduleIsRunning = false;
+                LOG.debug("Module {} was stopped.", module.getClass().getName());
+            } else if (isOwner && !moduleIsRunning) {
+                module.startModule();
+                moduleIsRunning = true;
+                LOG.debug("Module {} was restarted.", module.getClass().getName());
+            }
+        } else {
+            LOG.debug("Module wasn't initialized yet.");
+        }
+    }
+
+    public boolean isMaster() {
+        final Optional<EntityOwnershipState> ownershipState = entityOwnershipService.getOwnershipState(entity);
+        if (ownershipState.isPresent()) {
+            return ownershipState.get().isOwner();
+        } else {
+            LOG.debug("Ownership state information wasn't present in entity ownership service.");
+        }
+        return false;
+    }
+
+    public void setModule(final ClusterNodeModuleSwitcher module) {
+        this.module = module;
+    }
+}
diff --git a/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/api/ClusterNodeModuleSwitcher.java b/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/api/ClusterNodeModuleSwitcher.java
new file mode 100644 (file)
index 0000000..0d20ffe
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.lispflowmapping.clustering.api;
+
+/**
+ * Interface specify operations necessary to turn on|off module in node cluster.
+ */
+public interface ClusterNodeModuleSwitcher {
+
+    void startModule();
+
+    void stopModule();
+
+}
diff --git a/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/util/ClusteringUtil.java b/mappingservice/clustering/src/main/java/org/opendaylight/lispflowmapping/clustering/util/ClusteringUtil.java
new file mode 100644 (file)
index 0000000..0031252
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.lispflowmapping.clustering.util;
+
+public final class ClusteringUtil {
+
+    public static final String LISPFLOWMAPPING_ENTITY_NAME = "lispflowmapping";
+    public static final String LISPFLOWMAPPING_ENTITY_TYPE = "application";
+
+    private ClusteringUtil() {
+        throw new UnsupportedOperationException();
+    }
+
+}
diff --git a/mappingservice/clustering/src/main/test/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImplTest.java b/mappingservice/clustering/src/main/test/org/opendaylight/lispflowmapping/clustering/ClusterNodeModulSwitcherImplTest.java
new file mode 100644 (file)
index 0000000..c8d39fb
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.lispflowmapping.clustering;
+
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_NAME;
+import static org.opendaylight.lispflowmapping.clustering.util.ClusteringUtil.LISPFLOWMAPPING_ENTITY_TYPE;
+
+import com.google.common.base.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.lispflowmapping.clustering.api.ClusterNodeModuleSwitcher;
+
+public class ClusterNodeModulSwitcherImplTest  {
+
+    private EntityOwnershipService entityOwnershipServiceMocked;
+    private ClusterNodeModulSwitcherImpl clusterNodeModulSwitcherImpl;
+    private ClusterNodeModuleSwitcher module;
+    private Entity entity = new Entity(LISPFLOWMAPPING_ENTITY_NAME, LISPFLOWMAPPING_ENTITY_TYPE);
+
+    @Before
+    public void init() {
+        entityOwnershipServiceMocked = Mockito.mock(EntityOwnershipService.class);
+        clusterNodeModulSwitcherImpl = new ClusterNodeModulSwitcherImpl(entityOwnershipServiceMocked);
+        module = Mockito.mock(ClusterNodeModuleSwitcher.class);
+    }
+
+    @Test
+    public void constructorCallTest() throws CandidateAlreadyRegisteredException {
+        Mockito.verify(entityOwnershipServiceMocked).registerListener(Matchers.eq(LISPFLOWMAPPING_ENTITY_NAME),
+                Matchers.any(ClusterNodeModulSwitcherImpl.class));
+        Mockito.verify(entityOwnershipServiceMocked).registerCandidate(Matchers.eq(entity));
+    }
+
+    @Test
+    public void ownershipChangedTest() {
+        //is not owner
+        ownershipChanged(false);
+        Mockito.verify(module).stopModule();
+        //is owner
+        ownershipChanged(true);
+        Mockito.verify(module).startModule();
+    }
+
+    @Test
+    public void isMasterTest_OptionalAbsent() {
+        Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+                .absent
+                        ());
+        Assert.assertFalse(clusterNodeModulSwitcherImpl.isMaster());
+    }
+
+    @Test
+    public void isMasterTest_True() {
+        Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+                .of(new EntityOwnershipState(true, true)));
+        Assert.assertTrue(clusterNodeModulSwitcherImpl.isMaster());
+    }
+
+    @Test
+    public void isMasterTest_False() {
+        Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+                .of(new EntityOwnershipState(false, true)));
+        Assert.assertFalse(clusterNodeModulSwitcherImpl.isMaster());
+    }
+
+    @Test
+    public void switchModuleByEntityOwnershipTest() {
+        Mockito.when(entityOwnershipServiceMocked.getOwnershipState(Matchers.eq(entity))).thenReturn(Optional
+                .of(new EntityOwnershipState(false, true)));
+        clusterNodeModulSwitcherImpl.switchModuleByEntityOwnership();
+    }
+
+    private void ownershipChanged(boolean isOwner) {
+        final EntityOwnershipChange entityOwnershipChangeMock = Mockito.mock(EntityOwnershipChange.class);
+        clusterNodeModulSwitcherImpl.setModule(module);
+        Mockito.when(entityOwnershipChangeMock.isOwner()).thenReturn(isOwner);
+        clusterNodeModulSwitcherImpl.ownershipChanged(entityOwnershipChangeMock);
+    }
+}
index 97ac5550e7cc32aa666c14482f1b78a033663f70..39e319e3e48a897a577501f79324b9ec4520d7aa 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.lispflowmapping.implementation.mdsal;
 
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
@@ -19,7 +20,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * The superclass for the different MD-SAL data change event listeners.
  *
  */
-public abstract class AbstractDataListener<T extends DataObject> implements DataTreeChangeListener<T> {
+public abstract class AbstractDataListener<T extends DataObject> implements ClusteredDataTreeChangeListener<T> {
     private DataBroker broker;
     private InstanceIdentifier<T> path;
     private ListenerRegistration<DataTreeChangeListener<T>> registration;
index ab1b19cfc60301f730e066e3497e092f5da45310..f24a1e3ee95110f36c071c56e228b1d408f72cfa 100644 (file)
@@ -18,6 +18,7 @@
   <modules>
     <module>lisp-proto</module>
     <module>api</module>
+    <module>clustering</module>
     <module>inmemorydb</module>
     <module>dsbackend</module>
     <module>mapcache</module>
index d66ed11ca973998d9097053ff085dc883f108ef5..9496005b1ed9a3310bf0f5aa4041d7216a6b9d6e 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.lispflowmapping.southbound.lisp;
 
 import java.util.Collection;
 
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
@@ -32,7 +33,7 @@ import org.slf4j.LoggerFactory;
  * DataListener for all AuthenticationKey modification events.
  *
  */
-public class AuthenticationKeyDataListener implements DataTreeChangeListener<AuthenticationKey> {
+public class AuthenticationKeyDataListener implements ClusteredDataTreeChangeListener<AuthenticationKey> {
     private static final Logger LOG = LoggerFactory.getLogger(AuthenticationKeyDataListener.class);
 
     private final SimpleMapCache smc;