You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pr...@apache.org on 2018/04/02 17:02:57 UTC

[geode] branch develop updated: GEODE-4893: Improve reloading the cluster configuration on existing vanilla servers

This is an automated email from the ASF dual-hosted git repository.

prhomberg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 8b8cef1  GEODE-4893: Improve reloading the cluster configuration on existing vanilla servers
8b8cef1 is described below

commit 8b8cef12fa423cbd0e18dd9ddcf7793e8f0090c5
Author: jinmeiliao <ji...@pivotal.io>
AuthorDate: Mon Apr 2 10:02:53 2018 -0700

    GEODE-4893: Improve reloading the cluster configuration on existing vanilla servers
---
 .../cli/commands/ImportClusterConfigTest.java      | 60 ++++++++++++++++++
 .../geode/internal/cache/GemFireCacheImpl.java     | 13 ++++
 .../apache/geode/internal/cache/InternalCache.java |  2 +
 .../internal/cache/xmlcache/CacheCreation.java     |  5 ++
 .../ExportImportClusterConfigurationCommands.java  | 72 +++++++++++++---------
 .../functions/RecreateCacheFunction.java           | 20 +++---
 .../ClusterConfigDeployJarDUnitTest.java           |  4 ++
 .../ClusterConfigImportDUnitTest.java              | 34 +++++++++-
 .../ClusterConfigStartMemberDUnitTest.java         |  5 ++
 .../configuration/ClusterConfigTestBase.java       |  4 --
 10 files changed, 173 insertions(+), 46 deletions(-)

diff --git a/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/ImportClusterConfigTest.java b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/ImportClusterConfigTest.java
new file mode 100644
index 0000000..2b6a38b
--- /dev/null
+++ b/geode-assembly/src/test/java/org/apache/geode/management/internal/cli/commands/ImportClusterConfigTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.management.internal.configuration.ClusterConfigTestBase;
+import org.apache.geode.test.junit.categories.AcceptanceTest;
+import org.apache.geode.test.junit.rules.gfsh.GfshExecution;
+import org.apache.geode.test.junit.rules.gfsh.GfshRule;
+import org.apache.geode.test.junit.rules.gfsh.GfshScript;
+
+@Category(AcceptanceTest.class)
+public class ImportClusterConfigTest extends ClusterConfigTestBase {
+  private static final String locatorName = "locator";
+  private static final String serverNotShutDownName = "serverNotShutDown";
+
+  @Rule
+  public GfshRule gfsh = new GfshRule();
+
+  @Test
+  public void importWouldNotShutDownServer() {
+    GfshExecution startCluster = GfshScript
+        .of("start locator --name=" + locatorName, "start server --name=" + serverNotShutDownName)
+        .withName("startCluster").execute(gfsh);
+    assertThat(startCluster.getOutputText()).contains(locatorName + " is currently online")
+        .contains(serverNotShutDownName + " is currently online");
+
+    GfshExecution importConfiguration = GfshScript
+        .of("connect", "import cluster-configuration --zip-file-name=" + clusterConfigZipPath)
+        .withName("importConfiguration").execute(gfsh);
+    assertThat(importConfiguration.getOutputText())
+        .contains("Cluster configuration successfully imported").contains(
+            "Successfully applied the imported cluster configuration on " + serverNotShutDownName);
+
+    GfshExecution listMembers =
+        GfshScript.of("connect", "list members").withName("listMembers").execute(gfsh);
+    assertThat(listMembers.getOutputText()).contains("serverNotShutDown");
+  }
+
+}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index f6b35c1..3b69fa2 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -978,6 +978,19 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has
     } // synchronized
   }
 
+  @Override
+  public void reLoadClusterConfiguration() throws IOException, ClassNotFoundException {
+    this.configurationResponse = requestSharedConfiguration();
+    if (this.configurationResponse != null) {
+      ccLoader.deployJarsReceivedFromClusterConfiguration(this.configurationResponse);
+      ccLoader.applyClusterPropertiesConfiguration(this.configurationResponse,
+          this.system.getConfig());
+      ccLoader.applyClusterXmlConfiguration(this, this.configurationResponse,
+          this.system.getConfig().getGroups());
+      initializeDeclarativeCache();
+    }
+  }
+
   /**
    * Initialize the EventTracker's timer task. This is stored for tracking and shutdown purposes
    */
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/InternalCache.java b/geode-core/src/main/java/org/apache/geode/internal/cache/InternalCache.java
index d9f989f..dc05a3a 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/InternalCache.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/InternalCache.java
@@ -331,6 +331,8 @@ public interface InternalCache extends Cache, Extensible<Cache>, CacheTime {
 
   void waitForRegisterInterestsInProgress();
 
+  void reLoadClusterConfiguration() throws IOException, ClassNotFoundException;
+
   SecurityService getSecurityService();
 
   boolean hasPersistentRegion();
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheCreation.java b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheCreation.java
index ffc452e..3898a55 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheCreation.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/xmlcache/CacheCreation.java
@@ -1129,6 +1129,11 @@ public class CacheCreation implements InternalCache {
   }
 
   @Override
+  public void reLoadClusterConfiguration() throws IOException, ClassNotFoundException {
+    throw new UnsupportedOperationException(LocalizedStrings.SHOULDNT_INVOKE.toLocalizedString());
+  }
+
+  @Override
   public SecurityService getSecurityService() {
     return SecurityServiceFactory.create();
   }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
index 61118ba..c3a8eb5 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
@@ -35,7 +35,9 @@ import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 import org.xml.sax.SAXException;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalLocator;
@@ -133,23 +135,40 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman
           help = CliStrings.IMPORT_SHARED_CONFIG__ZIP__HELP) String zip)
       throws IOException, TransformerException, SAXException, ParserConfigurationException {
 
-    InternalLocator locator = InternalLocator.getLocator();
+    InternalClusterConfigurationService sc =
+        (InternalClusterConfigurationService) getConfigurationService();
 
-    if (!locator.isSharedConfigurationRunning()) {
-      ErrorResultData errorData = ResultBuilder.createErrorResultData();
-      errorData.addLine(CliStrings.SHARED_CONFIGURATION_NOT_STARTED);
-      return ResultBuilder.buildResult(errorData);
+    if (sc == null) {
+      return ResultBuilder.createGemFireErrorResult(CliStrings.SHARED_CONFIGURATION_NOT_STARTED);
     }
 
     Set<DistributedMember> servers = getAllNormalMembers();
 
-    Set<String> regionsWithData = servers.stream().map(this::getRegionNamesOnServer)
-        .flatMap(Collection::stream).collect(toSet());
+    // check if running servers are vanilla servers
+    if (servers.size() > 0) {
+      Set<String> groupNames = sc.getConfigurationRegion().keySet();
+      for (String groupName : groupNames) {
+        CacheConfig cacheConfig = sc.getCacheConfig(groupName);
+        if (cacheConfig.getRegion().size() > 0 || cacheConfig.getAsyncEventQueue().size() > 0
+            || cacheConfig.getDiskStore().size() > 0
+            || cacheConfig.getCustomCacheElements().size() > 0
+            || cacheConfig.getJndiBindings().size() > 0 || cacheConfig.getGatewayReceiver() != null
+            || cacheConfig.getGatewaySender().size() > 0) {
+          return ResultBuilder.createGemFireErrorResult(
+              "Running servers have existing cluster configuration applied already.");
+        }
+      }
 
-    if (!regionsWithData.isEmpty()) {
-      return ResultBuilder
-          .createGemFireErrorResult("Cannot import cluster configuration with existing regions: "
-              + regionsWithData.stream().collect(joining(",")));
+      // further checks in case any servers has regions not defined by the cluster configuration to
+      // avoid data loss.
+      Set<String> serverRegionNames = servers.stream().map(this::getRegionNamesOnServer)
+          .flatMap(Collection::stream).collect(toSet());
+
+      if (!serverRegionNames.isEmpty()) {
+        return ResultBuilder
+            .createGemFireErrorResult("Cannot import cluster configuration with existing regions: "
+                + serverRegionNames.stream().collect(joining(",")));
+      }
     }
 
     List<String> filePathFromShell = CommandExecutionContext.getFilePathFromShell();
@@ -158,8 +177,6 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman
     InfoResultData infoData = ResultBuilder.createInfoResultData();
     String zipFilePath = filePathFromShell.get(0);
 
-    InternalClusterConfigurationService sc = locator.getSharedConfiguration();
-
     // backup the old config
     for (Configuration config : sc.getConfigurationRegion().values()) {
       sc.writeConfigToFile(config);
@@ -173,16 +190,18 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman
     infoData.addLine(CliStrings.IMPORT_SHARED_CONFIG__SUCCESS__MSG);
 
     // Bounce the cache of each member
-    Set<CliFunctionResult> functionResults =
-        servers.stream().map(this::reCreateCache).collect(toSet());
-
-    for (CliFunctionResult functionResult : functionResults) {
-      if (functionResult.isSuccessful()) {
-        infoData.addLine("Successfully applied the imported cluster configuration on "
-            + functionResult.getMemberIdOrName());
-      } else {
-        infoData.addLine("Failed to apply the imported cluster configuration on "
-            + functionResult.getMemberIdOrName() + " due to " + functionResult.getMessage());
+    if (servers.size() > 0) {
+      List<CliFunctionResult> functionResults =
+          executeAndGetFunctionResult(new RecreateCacheFunction(), null, servers);
+
+      for (CliFunctionResult functionResult : functionResults) {
+        if (functionResult.isSuccessful()) {
+          infoData.addLine("Successfully applied the imported cluster configuration on "
+              + functionResult.getMemberIdOrName());
+        } else {
+          infoData.addLine("Failed to apply the imported cluster configuration on "
+              + functionResult.getMemberIdOrName() + " due to " + functionResult.getMessage());
+        }
       }
     }
 
@@ -197,13 +216,6 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman
     return results.get(0);
   }
 
-  private CliFunctionResult reCreateCache(DistributedMember server) {
-    ResultCollector rc = executeFunction(new RecreateCacheFunction(), null, server);
-    List<CliFunctionResult> results = (List<CliFunctionResult>) rc.getResult();
-
-    return results.get(0);
-  }
-
   /**
    * Interceptor used by gfsh to intercept execution of export shared config command at "shell".
    */
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/functions/RecreateCacheFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/functions/RecreateCacheFunction.java
index 1c0b40b..0b7892a 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/functions/RecreateCacheFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/functions/RecreateCacheFunction.java
@@ -14,30 +14,30 @@
  */
 package org.apache.geode.management.internal.configuration.functions;
 
+import org.apache.logging.log4j.Logger;
+
 import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.internal.cache.CacheConfig;
-import org.apache.geode.internal.cache.GemFireCacheImpl;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.execute.InternalFunction;
+import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 
 public class RecreateCacheFunction implements InternalFunction {
+  private static Logger logger = LogService.getLogger();
+
   @Override
   public void execute(FunctionContext context) {
     CliFunctionResult result = null;
     InternalCache cache = (InternalCache) context.getCache();
-    InternalDistributedSystem ds = cache.getInternalDistributedSystem();
-    CacheConfig cacheConfig = cache.getCacheConfig();
     try {
-      cache.close("Re-create Cache", true, true);
-      GemFireCacheImpl.create(ds, cacheConfig);
-    } catch (RuntimeException e) {
-      result = new CliFunctionResult(ds.getName(), e, e.getMessage());
+      cache.reLoadClusterConfiguration();
+    } catch (Exception e) {
+      logger.error(e.getMessage(), e);
+      result = new CliFunctionResult(context.getMemberName(), false, e.getMessage());
       context.getResultSender().lastResult(result);
       return;
     }
-    result = new CliFunctionResult(ds.getName(), true, "Cache successfully re-created.");
+    result = new CliFunctionResult(context.getMemberName(), true, "Cache successfully reloaded.");
     context.getResultSender().lastResult(result);
   }
 
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
index 5a1058f..8da9410 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigDeployJarDUnitTest.java
@@ -23,6 +23,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
 import org.apache.geode.test.junit.rules.GfshCommandRule;
@@ -35,6 +36,9 @@ public class ClusterConfigDeployJarDUnitTest extends ClusterConfigTestBase {
   private String group2Jar;
 
   @Rule
+  public ClusterStartupRule lsRule = new ClusterStartupRule();
+
+  @Rule
   public GfshCommandRule gfshConnector = new GfshCommandRule();
 
   @Before
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
index 31fcdf4..5487e49 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigImportDUnitTest.java
@@ -50,6 +50,9 @@ public class ClusterConfigImportDUnitTest extends ClusterConfigTestBase {
   private MemberVM locatorVM;
 
   @Rule
+  public ClusterStartupRule lsRule = new ClusterStartupRule();
+
+  @Rule
   public GfshCommandRule gfshConnector = new GfshCommandRule();
 
   @Before
@@ -87,8 +90,6 @@ public class ClusterConfigImportDUnitTest extends ClusterConfigTestBase {
     serverProps.setProperty("groups", "group2");
     MemberVM server2 = lsRule.startServerVM(2, serverProps, locatorVM.getPort());
 
-    // even though we have a region recreated, we can still import since there is no data
-    // in the region
     CommandResult result = gfshConnector
         .executeCommand("import cluster-configuration --zip-file-name=" + clusterConfigZipPath);
     assertThat(result.getContent().toString())
@@ -97,6 +98,35 @@ public class ClusterConfigImportDUnitTest extends ClusterConfigTestBase {
         .contains("Successfully applied the imported cluster configuration on server-2");
     new ClusterConfig(CLUSTER).verify(server1);
     new ClusterConfig(CLUSTER, GROUP2).verify(server2);
+
+    gfshConnector.executeAndAssertThat("list members").statusIsSuccess()
+        .tableHasColumnWithExactValuesInAnyOrder("Name", "locator-0", "server-1", "server-2");
+  }
+
+  @Test
+  public void importFailWithExistingDiskStore() {
+    lsRule.startServerVM(1, locatorVM.getPort());
+    gfshConnector.executeAndAssertThat("create disk-store --name=diskStore1 --dir=testStore")
+        .statusIsSuccess();
+    locatorVM.waitTillDiskstoreIsReady("diskStore1", 1);
+    gfshConnector
+        .executeAndAssertThat(
+            "import cluster-configuration --zip-file-name=" + clusterConfigZipPath)
+        .statusIsError()
+        .containsOutput("Running servers have existing cluster configuration applied already.");
+  }
+
+  @Test
+  public void importFailWithExistingRegion() {
+    lsRule.startServerVM(1, "group1", locatorVM.getPort());
+    gfshConnector
+        .executeAndAssertThat("create region --name=regionA --type=REPLICATE --group=group1")
+        .statusIsSuccess();
+    gfshConnector
+        .executeAndAssertThat(
+            "import cluster-configuration --zip-file-name=" + clusterConfigZipPath)
+        .statusIsError()
+        .containsOutput("Running servers have existing cluster configuration applied already.");
   }
 
   @Test
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
index bd8ba50..1fcafc6 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigStartMemberDUnitTest.java
@@ -24,10 +24,12 @@ import java.io.File;
 import java.util.Properties;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
 
@@ -36,6 +38,9 @@ public class ClusterConfigStartMemberDUnitTest extends ClusterConfigTestBase {
 
   private MemberVM locator;
 
+  @Rule
+  public ClusterStartupRule lsRule = new ClusterStartupRule();
+
   @Before
   public void before() throws Exception {
     locator = startLocatorWithLoadCCFromDir();
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
index ecc4d63..5831977 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/configuration/ClusterConfigTestBase.java
@@ -29,7 +29,6 @@ import org.junit.Rule;
 
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
 import org.apache.geode.test.compiler.ClassBuilder;
-import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
 
 public abstract class ClusterConfigTestBase {
@@ -55,9 +54,6 @@ public abstract class ClusterConfigTestBase {
   @Rule
   public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
 
-  @Rule
-  public ClusterStartupRule lsRule = new ClusterStartupRule();
-
   protected Properties locatorProps;
   protected Properties serverProps;
 

-- 
To stop receiving notification emails like this one, please contact
prhomberg@apache.org.