This is an automated email from the ASF dual-hosted git repository. DomGarguilo pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/accumulo.git
commit 2c9f94f7d011103389f90ba40b0c61acdd0b5c1e Merge: 403c99ddf9 2b2c3c8daa Author: Dom G <[email protected]> AuthorDate: Tue Oct 20 10:59:23 2026 -0400 Merge branch '2.1' into main .../accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java | 11 ++++++++--- .../main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --cc minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java index 9a4c4fd9bc,6e5af2ad17..8dba95d87f --- a/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java +++ b/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java @@@ -60,9 -61,11 +60,10 @@@ import java.util.stream.Collectors import java.util.stream.Stream; import org.apache.accumulo.cluster.AccumuloCluster; + import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.Accumulo; import org.apache.accumulo.core.client.AccumuloClient; -import org.apache.accumulo.core.client.AccumuloException; -import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; import org.apache.accumulo.core.clientImpl.ClientContext; import org.apache.accumulo.core.conf.AccumuloConfiguration; @@@ -620,15 -613,25 +621,19 @@@ public class MiniAccumuloClusterImpl im log.info("Starting MAC against instance {} and zookeeper(s) {}.", config.getInstanceName(), config.getZooKeepers()); - control.start(ServerType.TABLET_SERVER); - control.start(ServerType.SCAN_SERVER); - try (var reservation = SingletonManager.getClientReservation()) { - var zrw = new ZooReaderWriter(getSiteConfiguration()); - String instanceNamePath = - Constants.ZROOT + Constants.ZINSTANCES + "/" + config.getInstanceName(); - byte[] bytes = zrw.getData(instanceNamePath); - InstanceId iid = InstanceId.of(new String(bytes, UTF_8)); -- + try { + // fail fast before starting servers - they'll fail to start if this node exists already - final String upgradePrepNode = ZooUtil.getRoot(iid) + Constants.ZPREPARE_FOR_UPGRADE; - if (zrw.exists(upgradePrepNode)) { - throw new IllegalStateException( - "Cannot start, instance is prepared for upgrade: " + upgradePrepNode + " exists"); ++ if (getServerContext().getZooSession().asReader().exists(Constants.ZPREPARE_FOR_UPGRADE)) { ++ throw new IllegalStateException("Cannot start, instance is prepared for upgrade: " ++ + Constants.ZPREPARE_FOR_UPGRADE + " exists"); + } - SetGoalState.setGoalState(zrw, ZooUtil.getRoot(iid), ManagerGoalState.NORMAL); + SetGoalState.setGoalState(getServerContext(), ManagerGoalState.NORMAL); } catch (KeeperException e) { throw new IllegalStateException("Could not set manager goal state", e); } + control.start(ServerType.TABLET_SERVER); ++ control.start(ServerType.SCAN_SERVER); control.start(ServerType.MANAGER); control.start(ServerType.GARBAGE_COLLECTOR); diff --cc test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java index ce18e3f606,0000000000..10892c69bb mode 100644,000000..100644 --- a/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java +++ b/test/src/main/java/org/apache/accumulo/test/upgrade/UpgradeIT.java @@@ -1,175 -1,0 +1,176 @@@ +/* + * 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 + * + * https://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.accumulo.test.upgrade; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.time.Duration; + +import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.cli.ServerOpts; +import org.apache.accumulo.core.client.admin.servers.ServerId; +import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.conf.SiteConfiguration; +import org.apache.accumulo.core.fate.zookeeper.ZooReaderWriter; +import org.apache.accumulo.core.fate.zookeeper.ZooUtil.NodeExistsPolicy; +import org.apache.accumulo.core.lock.ServiceLock; +import org.apache.accumulo.core.lock.ServiceLockPaths.AddressSelector; +import org.apache.accumulo.core.lock.ServiceLockPaths.ResourceGroupPredicate; +import org.apache.accumulo.core.zookeeper.ZooSession; +import org.apache.accumulo.manager.Manager; +import org.apache.accumulo.minicluster.ServerType; +import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; +import org.apache.accumulo.server.AbstractServer; +import org.apache.accumulo.server.ServerContext; +import org.apache.accumulo.test.harness.AccumuloClusterHarness; +import org.apache.accumulo.test.util.Wait; +import org.apache.hadoop.conf.Configuration; +import org.junit.jupiter.api.Test; + +public class UpgradeIT extends AccumuloClusterHarness { + + private class ServerThatWontStart extends AbstractServer { + + protected ServerThatWontStart(String[] args) { + super(ServerId.Type.TABLET_SERVER, new ServerOpts(), (conf, rgid) -> new ServerContext(conf), + args); + } + + @Override + public void run() {} + + @Override + public ServiceLock getLock() { + return null; + } + + @Override + public void startServiceLockVerificationThread() {} + + @Override + public void close() {} + + } + + // This class exists because Manager constructor is not visible + private class TestManager extends Manager { + + protected TestManager(String[] args) throws IOException { + super(new ServerOpts(), (conf, rgid) -> new ServerContext(conf), args); + } + + @Override + public void startServiceLockVerificationThread() {} + + @Override + public void close() {} + + } + + @Override + protected Duration defaultTimeout() { + return Duration.ofMinutes(5); + } + + @Override + public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration hadoopCoreSite) { + cfg.setProperty(Property.INSTANCE_ZK_TIMEOUT, "15s"); + } + + @Test + public void testServersWontStart() throws Exception { + // Constants.ZPREPARE_FOR_UPGRADE is created by 'accumulo upgrade --prepare' + // which is run when the user wants to shutdown an instance in preparation + // to upgrade it. When this node exists, no servers should start. There is + // no ability to create this node in ZooKeeper before MAC starts for this + // test, so we will create the node after MAC starts, then try to restart + // MAC. + + final ZooSession zs = getServerContext().getZooSession(); + final ZooReaderWriter zrw = zs.asReaderWriter(); + final String upgradePath = Constants.ZPREPARE_FOR_UPGRADE; + zrw.putPersistentData(upgradePath, new byte[0], NodeExistsPolicy.SKIP); + + getCluster().stop(); + + getCluster().getClusterControl().startAllServers(ServerType.ZOOKEEPER); + + // Confirm all servers down + Wait.waitFor(() -> getServerContext().getServerPaths() + .getCompactor(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + Wait.waitFor(() -> getServerContext().getServerPaths().getGarbageCollector(true) == null); + Wait.waitFor(() -> getServerContext().getServerPaths().getManager(true) == null); + Wait.waitFor(() -> getServerContext().getServerPaths() + .getScanServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + Wait.waitFor(() -> getServerContext().getServerPaths() + .getTabletServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + - assertThrows(AssertionError.class, ++ var startIse = assertThrows(IllegalStateException.class, + () -> assertTimeoutPreemptively(Duration.ofMinutes(2), () -> getCluster().start())); ++ assertTrue(startIse.getMessage().startsWith("Cannot start, instance is prepared for upgrade")); + + // Confirm no servers started + Wait.waitFor(() -> getServerContext().getServerPaths() + .getCompactor(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + Wait.waitFor(() -> getServerContext().getServerPaths().getGarbageCollector(true) == null); + Wait.waitFor(() -> getServerContext().getServerPaths().getManager(true) == null); + Wait.waitFor(() -> getServerContext().getServerPaths() + .getScanServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + Wait.waitFor(() -> getServerContext().getServerPaths() + .getTabletServer(ResourceGroupPredicate.ANY, AddressSelector.all(), true).size() == 0); + + // Validate the exception from the servers + System.setProperty(SiteConfiguration.ACCUMULO_PROPERTIES_PROPERTY, + "file://" + getCluster().getAccumuloPropertiesPath()); + try { + IllegalStateException ise = + assertThrows(IllegalStateException.class, () -> new ServerThatWontStart(new String[0])); + assertTrue(ise.getMessage() + .startsWith("Instance has been prepared for upgrade to a minor or major version")); + } finally { + System.clearProperty(SiteConfiguration.ACCUMULO_PROPERTIES_PROPERTY); + } + + } + + @Test + public void testUpgradeManagerFailure() throws Exception { + // Test that the Manager fails when an upgrade is needed, + // but UpgradeProgressTracker.initialize was never called. + + getCluster().stop(); + getCluster().getClusterControl().startAllServers(ServerType.ZOOKEEPER); + + ServerContext ctx = getCluster().getServerContext(); + UpgradeUtilIT.downgradePersistentVersion(ctx); + + System.setProperty(SiteConfiguration.ACCUMULO_PROPERTIES_PROPERTY, + "file://" + getCluster().getAccumuloPropertiesPath()); + + try (TestManager mgr = new TestManager(new String[0])) { + IllegalStateException ise = assertThrows(IllegalStateException.class, () -> mgr.runServer()); + assertTrue(ise.getMessage().equals("Upgrade not started, " + Constants.ZUPGRADE_PROGRESS + + " node does not exist. Did you run 'accumulo upgrade --start'?")); + } + } + +}
