| /* |
| * 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.solr.cloud; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStreamWriter; |
| import java.io.Writer; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.Properties; |
| |
| import org.apache.solr.SolrTestCaseJ4; |
| import org.apache.solr.client.solrj.embedded.JettySolrRunner; |
| import org.apache.solr.client.solrj.request.CollectionAdminRequest; |
| import org.apache.solr.common.cloud.ClusterProperties; |
| import org.apache.solr.common.cloud.ClusterStateUtil; |
| import org.apache.solr.common.cloud.DocCollection; |
| import org.apache.solr.common.cloud.Replica; |
| import org.apache.solr.common.cloud.ZkStateReader; |
| import org.apache.solr.core.CorePropertiesLocator; |
| import org.junit.After; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| @SolrTestCaseJ4.SuppressSSL |
| public class LegacyCloudClusterPropTest extends SolrCloudTestCase { |
| |
| @BeforeClass |
| public static void setupCluster() throws Exception { |
| |
| // currently this test is fine with a single shard with a single replica and it's simpler. Could easily be |
| // extended to multiple shards/replicas, but there's no particular need. |
| configureCluster(1) |
| .addConfig("conf", configset("cloud-minimal")) |
| .configure(); |
| } |
| |
| @After |
| public void afterTest() throws Exception { |
| cluster.deleteAllCollections(); |
| } |
| |
| |
| // Are all these required? |
| private static String[] requiredProps = { |
| "numShards", |
| "collection.configName", |
| "name", |
| "replicaType", |
| "shard", |
| "collection", |
| "coreNodeName" |
| }; |
| |
| @Test |
| //2018-06-18 (commented) @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") |
| //Commented 14-Oct-2018 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // added 17-Aug-2018 |
| // commented out on: 01-Apr-2019 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // annotated on: 24-Dec-2018 |
| public void testCreateCollectionSwitchLegacyCloud() throws Exception { |
| createAndTest("legacyTrue", true); |
| createAndTest("legacyFalse", false); |
| } |
| |
| private void createAndTest(final String coll, final boolean legacy) throws Exception { |
| |
| // First, just insure that core.properties file gets created with coreNodeName and all other mandatory parameters. |
| final String legacyString = Boolean.toString(legacy); |
| final String legacyAnti = Boolean.toString(!legacy); |
| CollectionAdminRequest.setClusterProperty(ZkStateReader.LEGACY_CLOUD, legacyString).process(cluster.getSolrClient()); |
| ClusterProperties props = new ClusterProperties(zkClient()); |
| |
| assertEquals("Value of legacyCloud cluster prop unexpected", legacyString, |
| props.getClusterProperty(ZkStateReader.LEGACY_CLOUD, legacyAnti)); |
| |
| CollectionAdminRequest.createCollection(coll, "conf", 1, 1) |
| .setMaxShardsPerNode(1) |
| .process(cluster.getSolrClient()); |
| |
| cluster.waitForActiveCollection(coll, 1, 1); |
| |
| assertTrue(ClusterStateUtil.waitForAllActiveAndLiveReplicas(cluster.getSolrClient().getZkStateReader(), 120000)); |
| |
| // Insure all mandatory properties are there. |
| checkMandatoryProps(coll); |
| |
| checkCollectionActive(coll); |
| // The fixes for SOLR-11503 insure that creating a collection has coreNodeName whether legacyCloud is true or false, |
| // we still need to test repairing a properties file that does _not_ have coreNodeName set, the second part of |
| // the fix. |
| |
| // First, remove the coreNodeName from cluster.properties and write it out it. |
| removePropertyFromAllReplicas(coll, "coreNodeName"); |
| |
| // Now restart Solr, this should repair the removal on core load no matter the value of legacyCloud |
| JettySolrRunner jetty = cluster.getJettySolrRunner(0); |
| jetty.stop(); |
| |
| cluster.waitForJettyToStop(jetty); |
| |
| jetty.start(); |
| |
| cluster.waitForAllNodes(30); |
| |
| checkMandatoryProps(coll); |
| checkCollectionActive(coll); |
| } |
| |
| private void checkCollectionActive(String coll) { |
| assertTrue(ClusterStateUtil.waitForAllActiveAndLiveReplicas(cluster.getSolrClient().getZkStateReader(), 120000)); |
| DocCollection docColl = getCollectionState(coll); |
| for (Replica rep : docColl.getReplicas()) { |
| if (rep.getState() == Replica.State.ACTIVE) return; |
| } |
| fail("Replica was not active for collection " + coll); |
| } |
| private void removePropertyFromAllReplicas(String coll, String propDel) throws IOException { |
| DocCollection docColl = getCollectionState(coll); |
| |
| // First remove the property from all core.properties files |
| for (Replica rep : docColl.getReplicas()) { |
| final String coreName = rep.getCoreName(); |
| Properties prop = loadPropFileForReplica(coreName); |
| prop.remove(propDel); |
| JettySolrRunner jetty = cluster.getJettySolrRunner(0); |
| Path expected = Paths.get(jetty.getSolrHome()).toAbsolutePath().resolve(coreName); |
| Path corePropFile = Paths.get(expected.toString(), CorePropertiesLocator.PROPERTIES_FILENAME); |
| |
| try (Writer os = new OutputStreamWriter(Files.newOutputStream(corePropFile), StandardCharsets.UTF_8)) { |
| prop.store(os, ""); |
| } |
| } |
| |
| // Now insure it's really gone |
| for (Replica rep : docColl.getReplicas()) { |
| Properties prop = loadPropFileForReplica(rep.getCoreName()); |
| assertEquals("Property " + propDel + " should have been deleted", |
| "bogus", prop.getProperty(propDel, "bogus")); |
| } |
| } |
| |
| private Properties loadPropFileForReplica(String coreName) throws IOException { |
| JettySolrRunner jetty = cluster.getJettySolrRunner(0); |
| Path expected = Paths.get(jetty.getSolrHome()).toAbsolutePath().resolve(coreName); |
| Path corePropFile = Paths.get(expected.toString(), CorePropertiesLocator.PROPERTIES_FILENAME); |
| Properties props = new Properties(); |
| try (InputStream fis = Files.newInputStream(corePropFile)) { |
| props.load(new InputStreamReader(fis, StandardCharsets.UTF_8)); |
| } |
| return props; |
| } |
| |
| private void checkMandatoryProps(String coll) throws IOException { |
| DocCollection docColl = getCollectionState(coll); |
| for (Replica rep : docColl.getReplicas()) { |
| Properties prop = loadPropFileForReplica(rep.getCoreName()); for (String testProp : requiredProps) { |
| String propVal = prop.getProperty(testProp, "bogus"); |
| if ("bogus".equals(propVal)) { |
| fail("Should have found property " + testProp + " in properties file"); |
| } |
| } |
| } |
| } |
| } |