MultiClusterRepoAccessIT.java 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Licensed to Elasticsearch under one or more contributor
  3. * license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright
  5. * ownership. Elasticsearch licenses this file to you under
  6. * the Apache License, Version 2.0 (the "License"); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package org.elasticsearch.snapshots;
  20. import org.elasticsearch.common.network.NetworkModule;
  21. import org.elasticsearch.common.settings.Settings;
  22. import org.elasticsearch.core.internal.io.IOUtils;
  23. import org.elasticsearch.env.Environment;
  24. import org.elasticsearch.repositories.RepositoryException;
  25. import org.elasticsearch.snapshots.mockstore.MockRepository;
  26. import org.elasticsearch.test.ESIntegTestCase;
  27. import org.elasticsearch.test.InternalSettingsPlugin;
  28. import org.elasticsearch.test.InternalTestCluster;
  29. import org.elasticsearch.test.MockHttpTransport;
  30. import org.elasticsearch.test.NodeConfigurationSource;
  31. import org.elasticsearch.test.transport.MockTransportService;
  32. import org.elasticsearch.transport.nio.MockNioTransportPlugin;
  33. import org.junit.After;
  34. import org.junit.Before;
  35. import java.io.IOException;
  36. import java.nio.file.Path;
  37. import java.util.Arrays;
  38. import java.util.function.Function;
  39. import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
  40. import static org.hamcrest.Matchers.containsString;
  41. import static org.hamcrest.Matchers.equalTo;
  42. import static org.hamcrest.Matchers.not;
  43. public class MultiClusterRepoAccessIT extends AbstractSnapshotIntegTestCase {
  44. private InternalTestCluster secondCluster;
  45. private Path repoPath;
  46. @Before
  47. public void startSecondCluster() throws IOException, InterruptedException {
  48. repoPath = randomRepoPath();
  49. secondCluster = new InternalTestCluster(randomLong(), createTempDir(), true, true, 0,
  50. 0, "second_cluster", new NodeConfigurationSource() {
  51. @Override
  52. public Settings nodeSettings(int nodeOrdinal) {
  53. return Settings.builder().put(MultiClusterRepoAccessIT.this.nodeSettings(nodeOrdinal))
  54. .put(NetworkModule.TRANSPORT_TYPE_KEY, getTestTransportType())
  55. .put(Environment.PATH_REPO_SETTING.getKey(), repoPath).build();
  56. }
  57. @Override
  58. public Path nodeConfigPath(int nodeOrdinal) {
  59. return null;
  60. }
  61. }, 0, "leader", Arrays.asList(ESIntegTestCase.TestSeedPlugin.class,
  62. MockHttpTransport.TestPlugin.class, MockTransportService.TestPlugin.class,
  63. MockNioTransportPlugin.class, InternalSettingsPlugin.class, MockRepository.Plugin.class), Function.identity());
  64. secondCluster.beforeTest(random());
  65. }
  66. @After
  67. public void stopSecondCluster() throws IOException {
  68. IOUtils.close(secondCluster);
  69. }
  70. public void testConcurrentDeleteFromOtherCluster() throws InterruptedException {
  71. internalCluster().startMasterOnlyNode();
  72. internalCluster().startDataOnlyNode();
  73. final String repoNameOnFirstCluster = "test-repo";
  74. final String repoNameOnSecondCluster = randomBoolean() ? "test-repo" : "other-repo";
  75. createRepository(repoNameOnFirstCluster, "fs", repoPath);
  76. secondCluster.startMasterOnlyNode();
  77. secondCluster.startDataOnlyNode();
  78. createIndexWithRandomDocs("test-idx-1", randomIntBetween(1, 100));
  79. createFullSnapshot(repoNameOnFirstCluster, "snap-1");
  80. createIndexWithRandomDocs("test-idx-2", randomIntBetween(1, 100));
  81. createFullSnapshot(repoNameOnFirstCluster, "snap-2");
  82. createIndexWithRandomDocs("test-idx-3", randomIntBetween(1, 100));
  83. createFullSnapshot(repoNameOnFirstCluster, "snap-3");
  84. secondCluster.client().admin().cluster().preparePutRepository(repoNameOnSecondCluster).setType("fs")
  85. .setSettings(Settings.builder().put("location", repoPath)).get();
  86. secondCluster.client().admin().cluster().prepareDeleteSnapshot(repoNameOnSecondCluster, "snap-1").get();
  87. secondCluster.client().admin().cluster().prepareDeleteSnapshot(repoNameOnSecondCluster, "snap-2").get();
  88. final SnapshotException sne = expectThrows(SnapshotException.class, () ->
  89. client().admin().cluster().prepareCreateSnapshot(repoNameOnFirstCluster, "snap-4").setWaitForCompletion(true)
  90. .execute().actionGet());
  91. assertThat(sne.getMessage(), containsString("failed to update snapshot in repository"));
  92. final RepositoryException cause = (RepositoryException) sne.getCause();
  93. assertThat(cause.getMessage(), containsString("[" + repoNameOnFirstCluster +
  94. "] concurrent modification of the index-N file, expected current generation [2] but it was not found in the repository"));
  95. assertAcked(client().admin().cluster().prepareDeleteRepository(repoNameOnFirstCluster).get());
  96. createRepository(repoNameOnFirstCluster, "fs", repoPath);
  97. createFullSnapshot(repoNameOnFirstCluster, "snap-5");
  98. }
  99. public void testConcurrentWipeAndRecreateFromOtherCluster() throws InterruptedException, IOException {
  100. internalCluster().startMasterOnlyNode();
  101. internalCluster().startDataOnlyNode();
  102. final String repoName = "test-repo";
  103. createRepository(repoName, "fs", repoPath);
  104. createIndexWithRandomDocs("test-idx-1", randomIntBetween(1, 100));
  105. createFullSnapshot(repoName, "snap-1");
  106. final String repoUuid = client().admin().cluster().prepareGetRepositories(repoName).get().repositories()
  107. .stream().filter(r -> r.name().equals(repoName)).findFirst().orElseThrow().uuid();
  108. secondCluster.startMasterOnlyNode();
  109. secondCluster.startDataOnlyNode();
  110. assertAcked(secondCluster.client().admin().cluster().preparePutRepository(repoName)
  111. .setType("fs")
  112. .setSettings(Settings.builder().put("location", repoPath).put("readonly", true)));
  113. assertThat(secondCluster.client().admin().cluster().prepareGetRepositories(repoName).get().repositories()
  114. .stream().filter(r -> r.name().equals(repoName)).findFirst().orElseThrow().uuid(), equalTo(repoUuid));
  115. assertAcked(client().admin().cluster().prepareDeleteRepository(repoName));
  116. IOUtils.rm(internalCluster().getCurrentMasterNodeInstance(Environment.class).resolveRepoFile(repoPath.toString()));
  117. createRepository(repoName, "fs", repoPath);
  118. createFullSnapshot(repoName, "snap-1");
  119. final String newRepoUuid = client().admin().cluster().prepareGetRepositories(repoName).get().repositories()
  120. .stream().filter(r -> r.name().equals(repoName)).findFirst().orElseThrow().uuid();
  121. assertThat(newRepoUuid, not(equalTo((repoUuid))));
  122. secondCluster.client().admin().cluster().prepareGetSnapshots(repoName).get(); // force another read of the repo data
  123. assertThat(secondCluster.client().admin().cluster().prepareGetRepositories(repoName).get().repositories()
  124. .stream().filter(r -> r.name().equals(repoName)).findFirst().orElseThrow().uuid(), equalTo(newRepoUuid));
  125. }
  126. }