You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by mm...@apache.org on 2021/08/17 13:51:30 UTC

[accumulo] branch main updated: Drop ServerUtil and static state (#2233)

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

mmiller pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new efbaf2d  Drop ServerUtil and static state (#2233)
efbaf2d is described below

commit efbaf2d52d10110d8dbbec0a11daf5c596f2d278
Author: Mike Miller <mm...@apache.org>
AuthorDate: Tue Aug 17 09:51:23 2021 -0400

    Drop ServerUtil and static state (#2233)
    
    * Move static state from ServerUtil in to ServerConstants object methods
    * Move creation of ServerConstants object into ServerInfo
    * Move upgrade code from ServerUtil into UpgradeCoordinator
    * Move methods dealing with server stuff to ServerContext
    * Create getter for ServerConstants in ServerContext
    * Move AccumuloTest to manager to avoid adding a dependency
    * Drop ServerUtilTest and move testing of method to ServerContextTest
    * Make InterruptedException handled the same as other KeeperException
    in ServerContext waitForZookeeperAndHdfs()
    
    Co-authored-by: EdColeman <de...@etcoleman.com>
---
 .../miniclusterImpl/MiniAccumuloClusterImpl.java   |   5 +-
 .../org/apache/accumulo/server/AbstractServer.java |   2 +-
 .../apache/accumulo/server/ServerConstants.java    |  37 ++-
 .../org/apache/accumulo/server/ServerContext.java  | 156 ++++++++++-
 .../org/apache/accumulo/server/ServerInfo.java     |  10 +-
 .../org/apache/accumulo/server/ServerUtil.java     | 288 ---------------------
 .../apache/accumulo/server/init/Initialize.java    |  10 +-
 .../apache/accumulo/server/util/ChangeSecret.java  |  20 +-
 .../apache/accumulo/server/ServerContextTest.java  |   6 +
 .../org/apache/accumulo/server/ServerUtilTest.java |  29 ---
 .../accumulo/manager/state/SetGoalState.java       |   3 +-
 .../manager/upgrade/UpgradeCoordinator.java        |  79 +++++-
 .../accumulo/manager/upgrade}/AccumuloTest.java    |  26 +-
 .../org/apache/accumulo/tracer/TraceServer.java    |   3 +-
 14 files changed, 318 insertions(+), 356 deletions(-)

diff --git a/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java b/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
index 7b315e8..679f725 100644
--- a/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
+++ b/minicluster/src/main/java/org/apache/accumulo/miniclusterImpl/MiniAccumuloClusterImpl.java
@@ -78,8 +78,8 @@ import org.apache.accumulo.fate.zookeeper.ZooUtil;
 import org.apache.accumulo.manager.state.SetGoalState;
 import org.apache.accumulo.minicluster.MiniAccumuloCluster;
 import org.apache.accumulo.minicluster.ServerType;
+import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.ServerUtil;
 import org.apache.accumulo.server.fs.VolumeManager;
 import org.apache.accumulo.server.fs.VolumeManagerImpl;
 import org.apache.accumulo.server.init.Initialize;
@@ -470,11 +470,12 @@ public class MiniAccumuloClusterImpl implements AccumuloCluster {
     if (config.useExistingInstance()) {
       AccumuloConfiguration acuConf = config.getAccumuloConfiguration();
       Configuration hadoopConf = config.getHadoopConfiguration();
+      ServerConstants serverConstants = new ServerConstants(acuConf, hadoopConf);
 
       ConfigurationCopy cc = new ConfigurationCopy(acuConf);
       Path instanceIdPath;
       try (var fs = VolumeManagerImpl.get(cc, hadoopConf)) {
-        instanceIdPath = ServerUtil.getAccumuloInstanceIdPath(fs);
+        instanceIdPath = serverConstants.getInstanceIdLocation(fs.getFirst());
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java b/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java
index f2ebe63..49e03b0 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java
@@ -49,7 +49,7 @@ public abstract class AbstractServer implements AutoCloseable, Runnable {
     context = new ServerContext(siteConfig);
     log.info("Version " + Constants.VERSION);
     log.info("Instance " + context.getInstanceID());
-    ServerUtil.init(context, appName);
+    context.init(appName);
     ClassLoaderUtil.initContextFactory(context.getConfiguration());
     this.metricsSystem = Metrics.initSystem(getClass().getSimpleName());
     TraceUtil.enableServerTraces(hostname, appName, context.getConfiguration());
diff --git a/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java b/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
index 46d39f1..0195e8c 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/ServerConstants.java
@@ -18,6 +18,7 @@
  */
 package org.apache.accumulo.server;
 
+import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -32,10 +33,13 @@ import java.util.stream.Collectors;
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.Property;
 import org.apache.accumulo.core.util.Pair;
+import org.apache.accumulo.core.volume.Volume;
 import org.apache.accumulo.core.volume.VolumeConfiguration;
 import org.apache.accumulo.server.fs.VolumeManager;
 import org.apache.accumulo.server.fs.VolumeUtil;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 
 import com.google.common.collect.Sets;
@@ -124,8 +128,7 @@ public class ServerConstants {
       try {
         currentIid = VolumeManager.getInstanceIDFromHdfs(path, hadoopConf);
         Path vpath = new Path(baseDir, VERSION_DIR);
-        currentVersion =
-            ServerUtil.getAccumuloPersistentVersion(vpath.getFileSystem(hadoopConf), vpath);
+        currentVersion = getAccumuloPersistentVersion(vpath.getFileSystem(hadoopConf), vpath);
       } catch (Exception e) {
         if (ignore) {
           continue;
@@ -248,4 +251,34 @@ public class ServerConstants {
   public List<Pair<Path,Path>> getVolumeReplacements() {
     return this.replacementsList;
   }
+
+  public Path getDataVersionLocation(Volume v) {
+    // all base dirs should have the same version, so can choose any one
+    return v.prefixChild(VERSION_DIR);
+  }
+
+  public int getAccumuloPersistentVersion(Volume v) {
+    Path path = getDataVersionLocation(v);
+    return getAccumuloPersistentVersion(v.getFileSystem(), path);
+  }
+
+  public int getAccumuloPersistentVersion(FileSystem fs, Path path) {
+    int dataVersion;
+    try {
+      FileStatus[] files = fs.listStatus(path);
+      if (files == null || files.length == 0) {
+        dataVersion = -1; // assume it is 0.5 or earlier
+      } else {
+        dataVersion = Integer.parseInt(files[0].getPath().getName());
+      }
+      return dataVersion;
+    } catch (IOException e) {
+      throw new RuntimeException("Unable to read accumulo version: an error occurred.", e);
+    }
+  }
+
+  public Path getInstanceIdLocation(Volume v) {
+    // all base dirs should have the same instance id, so can choose any one
+    return v.prefixChild(ServerConstants.INSTANCE_ID_DIR);
+  }
 }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/ServerContext.java b/server/base/src/main/java/org/apache/accumulo/server/ServerContext.java
index 85507fe..6056f47 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/ServerContext.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/ServerContext.java
@@ -19,11 +19,22 @@
 package org.apache.accumulo.server;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.accumulo.fate.util.UtilWaitThread.sleepUninterruptibly;
 
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 
+import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.clientImpl.ClientContext;
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 import org.apache.accumulo.core.conf.DefaultConfiguration;
@@ -37,7 +48,9 @@ import org.apache.accumulo.core.metadata.schema.Ample;
 import org.apache.accumulo.core.rpc.SslConnectionParams;
 import org.apache.accumulo.core.singletons.SingletonReservation;
 import org.apache.accumulo.core.spi.crypto.CryptoService;
+import org.apache.accumulo.core.util.AddressUtil;
 import org.apache.accumulo.core.util.Pair;
+import org.apache.accumulo.core.util.threads.ThreadPools;
 import org.apache.accumulo.fate.zookeeper.ZooCache;
 import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
 import org.apache.accumulo.server.conf.NamespaceConfiguration;
@@ -54,12 +67,16 @@ import org.apache.accumulo.server.tables.TableManager;
 import org.apache.accumulo.server.tablets.UniqueNameAllocator;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.zookeeper.KeeperException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Provides a server context for Accumulo server components that operate with the system credentials
  * and have access to the system files and configuration.
  */
 public class ServerContext extends ClientContext {
+  private static final Logger log = LoggerFactory.getLogger(ServerContext.class);
 
   private final ServerInfo info;
   private final ZooReaderWriter zooReaderWriter;
@@ -81,7 +98,7 @@ public class ServerContext extends ClientContext {
     super(SingletonReservation.noop(), info, info.getSiteConfiguration());
     this.info = info;
     zooReaderWriter = new ZooReaderWriter(info.getSiteConfiguration());
-    serverConstants = new ServerConstants(info.getSiteConfiguration(), info.getHadoopConf());
+    serverConstants = info.getServerConstants();
   }
 
   /**
@@ -154,6 +171,10 @@ public class ServerContext extends ClientContext {
     return defaultConfig;
   }
 
+  public ServerConstants getServerConstants() {
+    return serverConstants;
+  }
+
   /**
    * A "client-side" assertion for servers to validate that they are logged in as the expected user,
    * per the configuration, before performing any RPC
@@ -279,4 +300,137 @@ public class ServerContext extends ClientContext {
   public Set<String> getRecoveryDirs() {
     return serverConstants.getRecoveryDirs();
   }
+
+  /**
+   * Check to see if this version of Accumulo can run against or upgrade the passed in data version.
+   */
+  public static void ensureDataVersionCompatible(int dataVersion) {
+    if (!(ServerConstants.CAN_RUN.contains(dataVersion))) {
+      throw new IllegalStateException("This version of accumulo (" + Constants.VERSION
+          + ") is not compatible with files stored using data version " + dataVersion);
+    }
+  }
+
+  public void waitForZookeeperAndHdfs() {
+    log.info("Attempting to talk to zookeeper");
+    while (true) {
+      try {
+        getZooReaderWriter().getChildren(Constants.ZROOT);
+        break;
+      } catch (InterruptedException | KeeperException ex) {
+        log.info("Waiting for accumulo to be initialized");
+        sleepUninterruptibly(1, TimeUnit.SECONDS);
+      }
+    }
+    log.info("ZooKeeper connected and initialized, attempting to talk to HDFS");
+    long sleep = 1000;
+    int unknownHostTries = 3;
+    while (true) {
+      try {
+        if (getVolumeManager().isReady())
+          break;
+        log.warn("Waiting for the NameNode to leave safemode");
+      } catch (IOException ex) {
+        log.warn("Unable to connect to HDFS", ex);
+      } catch (IllegalArgumentException e) {
+        /* Unwrap the UnknownHostException so we can deal with it directly */
+        if (e.getCause() instanceof UnknownHostException) {
+          if (unknownHostTries > 0) {
+            log.warn("Unable to connect to HDFS, will retry. cause: {}", e.getCause());
+            /*
+             * We need to make sure our sleep period is long enough to avoid getting a cached
+             * failure of the host lookup.
+             */
+            int ttl = AddressUtil.getAddressCacheNegativeTtl((UnknownHostException) e.getCause());
+            sleep = Math.max(sleep, (ttl + 1) * 1000L);
+          } else {
+            log.error("Unable to connect to HDFS and exceeded the maximum number of retries.", e);
+            throw e;
+          }
+          unknownHostTries--;
+        } else {
+          throw e;
+        }
+      }
+      log.info("Backing off due to failure; current sleep period is {} seconds", sleep / 1000.);
+      sleepUninterruptibly(sleep, TimeUnit.MILLISECONDS);
+      /* Back off to give transient failures more time to clear. */
+      sleep = Math.min(60 * 1000, sleep * 2);
+    }
+    log.info("Connected to HDFS");
+  }
+
+  /**
+   * Wait for ZK and hdfs, check data version and some properties, and start thread to monitor
+   * swappiness. Should only be called once during server start up.
+   */
+  public void init(String application) {
+    final AccumuloConfiguration conf = getConfiguration();
+
+    log.info("{} starting", application);
+    log.info("Instance {}", getInstanceID());
+    // It doesn't matter which Volume is used as they should all have the data version stored
+    int dataVersion = serverConstants.getAccumuloPersistentVersion(getVolumeManager().getFirst());
+    log.info("Data Version {}", dataVersion);
+    waitForZookeeperAndHdfs();
+
+    ensureDataVersionCompatible(dataVersion);
+
+    TreeMap<String,String> sortedProps = new TreeMap<>();
+    for (Map.Entry<String,String> entry : conf)
+      sortedProps.put(entry.getKey(), entry.getValue());
+
+    for (Map.Entry<String,String> entry : sortedProps.entrySet()) {
+      String key = entry.getKey();
+      log.info("{} = {}", key, (Property.isSensitive(key) ? "<hidden>" : entry.getValue()));
+      Property prop = Property.getPropertyByKey(key);
+      if (prop != null && conf.isPropertySet(prop, false)) {
+        if (prop.isDeprecated()) {
+          Property replacedBy = prop.replacedBy();
+          if (replacedBy != null) {
+            log.warn("{} is deprecated, use {} instead.", prop.getKey(), replacedBy.getKey());
+          } else {
+            log.warn("{} is deprecated", prop.getKey());
+          }
+        }
+      }
+    }
+
+    monitorSwappiness(conf);
+
+    // Encourage users to configure TLS
+    final String SSL = "SSL";
+    for (Property sslProtocolProperty : Arrays.asList(Property.RPC_SSL_CLIENT_PROTOCOL,
+        Property.RPC_SSL_ENABLED_PROTOCOLS, Property.MONITOR_SSL_INCLUDE_PROTOCOLS)) {
+      String value = conf.get(sslProtocolProperty);
+      if (value.contains(SSL)) {
+        log.warn("It is recommended that {} only allow TLS", sslProtocolProperty);
+      }
+    }
+  }
+
+  private void monitorSwappiness(AccumuloConfiguration config) {
+    ThreadPools.createGeneralScheduledExecutorService(config).scheduleWithFixedDelay(() -> {
+      try {
+        String procFile = "/proc/sys/vm/swappiness";
+        File swappiness = new File(procFile);
+        if (swappiness.exists() && swappiness.canRead()) {
+          try (InputStream is = new FileInputStream(procFile)) {
+            byte[] buffer = new byte[10];
+            int bytes = is.read(buffer);
+            String setting = new String(buffer, 0, bytes, UTF_8);
+            setting = setting.trim();
+            if (bytes > 0 && Integer.parseInt(setting) > 10) {
+              log.warn("System swappiness setting is greater than ten ({})"
+                  + " which can cause time-sensitive operations to be delayed."
+                  + " Accumulo is time sensitive because it needs to maintain"
+                  + " distributed lock agreement.", setting);
+            }
+          }
+        }
+      } catch (Exception t) {
+        log.error("", t);
+      }
+    }, 1000, 10 * 60 * 1000, TimeUnit.MILLISECONDS);
+  }
 }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/ServerInfo.java b/server/base/src/main/java/org/apache/accumulo/server/ServerInfo.java
index 97e8a9a..c6d3dab 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/ServerInfo.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/ServerInfo.java
@@ -53,6 +53,7 @@ public class ServerInfo implements ClientInfo {
   private int zooKeepersSessionTimeOut;
   private VolumeManager volumeManager;
   private ZooCache zooCache;
+  private final ServerConstants serverConstants;
 
   ServerInfo(SiteConfiguration siteConfig, String instanceName, String zooKeepers,
       int zooKeepersSessionTimeOut) {
@@ -82,6 +83,7 @@ public class ServerInfo implements ClientInfo {
       throw new RuntimeException("Instance id " + instanceID + " pointed to by the name "
           + instanceName + " does not exist in zookeeper");
     }
+    serverConstants = new ServerConstants(siteConfig, hadoopConf);
   }
 
   ServerInfo(SiteConfiguration config) {
@@ -93,7 +95,8 @@ public class ServerInfo implements ClientInfo {
     } catch (IOException e) {
       throw new IllegalStateException(e);
     }
-    Path instanceIdPath = ServerUtil.getAccumuloInstanceIdPath(volumeManager);
+    serverConstants = new ServerConstants(siteConfig, hadoopConf);
+    Path instanceIdPath = serverConstants.getInstanceIdLocation(volumeManager.getFirst());
     instanceID = VolumeManager.getInstanceIDFromHdfs(instanceIdPath, hadoopConf);
     zooKeepers = config.get(Property.INSTANCE_ZK_HOST);
     zooKeepersSessionTimeOut = (int) config.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT);
@@ -115,6 +118,7 @@ public class ServerInfo implements ClientInfo {
     zooKeepersSessionTimeOut = (int) config.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT);
     zooCache = new ZooCacheFactory().getZooCache(zooKeepers, zooKeepersSessionTimeOut);
     this.instanceName = instanceName;
+    serverConstants = new ServerConstants(siteConfig, hadoopConf);
   }
 
   public SiteConfiguration getSiteConfiguration() {
@@ -179,4 +183,8 @@ public class ServerInfo implements ClientInfo {
   public Configuration getHadoopConf() {
     return this.hadoopConf;
   }
+
+  public ServerConstants getServerConstants() {
+    return serverConstants;
+  }
 }
diff --git a/server/base/src/main/java/org/apache/accumulo/server/ServerUtil.java b/server/base/src/main/java/org/apache/accumulo/server/ServerUtil.java
deleted file mode 100644
index f864972..0000000
--- a/server/base/src/main/java/org/apache/accumulo/server/ServerUtil.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * 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.accumulo.server;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.accumulo.fate.util.UtilWaitThread.sleepUninterruptibly;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Map.Entry;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.accumulo.core.Constants;
-import org.apache.accumulo.core.client.AccumuloException;
-import org.apache.accumulo.core.conf.AccumuloConfiguration;
-import org.apache.accumulo.core.conf.Property;
-import org.apache.accumulo.core.util.AddressUtil;
-import org.apache.accumulo.core.util.threads.ThreadPools;
-import org.apache.accumulo.core.volume.Volume;
-import org.apache.accumulo.fate.ReadOnlyStore;
-import org.apache.accumulo.fate.ReadOnlyTStore;
-import org.apache.accumulo.fate.ZooStore;
-import org.apache.accumulo.server.fs.VolumeManager;
-import org.apache.hadoop.fs.FileStatus;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.zookeeper.KeeperException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ServerUtil {
-
-  private static final Logger log = LoggerFactory.getLogger(ServerUtil.class);
-
-  public static synchronized void updateAccumuloVersion(VolumeManager fs, int oldVersion) {
-    for (Volume volume : fs.getVolumes()) {
-      try {
-        if (getAccumuloPersistentVersion(volume) == oldVersion) {
-          log.debug("Attempting to upgrade {}", volume);
-          Path dataVersionLocation = getDataVersionLocation(volume);
-          fs.create(new Path(dataVersionLocation, Integer.toString(ServerConstants.DATA_VERSION)))
-              .close();
-          // TODO document failure mode & recovery if FS permissions cause above to work and below
-          // to fail ACCUMULO-2596
-          Path prevDataVersionLoc = new Path(dataVersionLocation, Integer.toString(oldVersion));
-          if (!fs.delete(prevDataVersionLoc)) {
-            throw new RuntimeException("Could not delete previous data version location ("
-                + prevDataVersionLoc + ") for " + volume);
-          }
-        }
-      } catch (IOException e) {
-        throw new RuntimeException("Unable to set accumulo version: an error occurred.", e);
-      }
-    }
-  }
-
-  public static synchronized int getAccumuloPersistentVersion(FileSystem fs, Path path) {
-    int dataVersion;
-    try {
-      FileStatus[] files = fs.listStatus(path);
-      if (files == null || files.length == 0) {
-        dataVersion = -1; // assume it is 0.5 or earlier
-      } else {
-        dataVersion = Integer.parseInt(files[0].getPath().getName());
-      }
-      return dataVersion;
-    } catch (IOException e) {
-      throw new RuntimeException("Unable to read accumulo version: an error occurred.", e);
-    }
-  }
-
-  public static synchronized int getAccumuloPersistentVersion(Volume v) {
-    Path path = getDataVersionLocation(v);
-    return getAccumuloPersistentVersion(v.getFileSystem(), path);
-  }
-
-  public static synchronized int getAccumuloPersistentVersion(VolumeManager vm) {
-    // It doesn't matter which Volume is used as they should all have the data version stored
-    return getAccumuloPersistentVersion(vm.getFirst());
-  }
-
-  public static synchronized Path getAccumuloInstanceIdPath(VolumeManager vm) {
-    // It doesn't matter which Volume is used as they should all have the instance ID stored
-    return getInstanceIdLocation(vm.getFirst());
-  }
-
-  public static Path getInstanceIdLocation(Volume v) {
-    // all base dirs should have the same instance id, so can choose any one
-    return v.prefixChild(ServerConstants.INSTANCE_ID_DIR);
-  }
-
-  public static Path getDataVersionLocation(Volume v) {
-    // all base dirs should have the same version, so can choose any one
-    return v.prefixChild(ServerConstants.VERSION_DIR);
-  }
-
-  public static void init(ServerContext context, String application) {
-    final AccumuloConfiguration conf = context.getConfiguration();
-
-    log.info("{} starting", application);
-    log.info("Instance {}", context.getInstanceID());
-    int dataVersion = ServerUtil.getAccumuloPersistentVersion(context.getVolumeManager());
-    log.info("Data Version {}", dataVersion);
-    ServerUtil.waitForZookeeperAndHdfs(context);
-
-    ensureDataVersionCompatible(dataVersion);
-
-    TreeMap<String,String> sortedProps = new TreeMap<>();
-    for (Entry<String,String> entry : conf)
-      sortedProps.put(entry.getKey(), entry.getValue());
-
-    for (Entry<String,String> entry : sortedProps.entrySet()) {
-      String key = entry.getKey();
-      log.info("{} = {}", key, (Property.isSensitive(key) ? "<hidden>" : entry.getValue()));
-      Property prop = Property.getPropertyByKey(key);
-      if (prop != null && conf.isPropertySet(prop, false)) {
-        if (prop.isDeprecated()) {
-          Property replacedBy = prop.replacedBy();
-          if (replacedBy != null) {
-            log.warn("{} is deprecated, use {} instead.", prop.getKey(), replacedBy.getKey());
-          } else {
-            log.warn("{} is deprecated", prop.getKey());
-          }
-        }
-      }
-    }
-
-    monitorSwappiness(conf);
-
-    // Encourage users to configure TLS
-    final String SSL = "SSL";
-    for (Property sslProtocolProperty : Arrays.asList(Property.RPC_SSL_CLIENT_PROTOCOL,
-        Property.RPC_SSL_ENABLED_PROTOCOLS, Property.MONITOR_SSL_INCLUDE_PROTOCOLS)) {
-      String value = conf.get(sslProtocolProperty);
-      if (value.contains(SSL)) {
-        log.warn("It is recommended that {} only allow TLS", sslProtocolProperty);
-      }
-    }
-  }
-
-  /**
-   * Check to see if this version of Accumulo can run against or upgrade the passed in data version.
-   */
-  public static void ensureDataVersionCompatible(int dataVersion) {
-    if (!(ServerConstants.CAN_RUN.contains(dataVersion))) {
-      throw new IllegalStateException("This version of accumulo (" + Constants.VERSION
-          + ") is not compatible with files stored using data version " + dataVersion);
-    }
-  }
-
-  /**
-   * Does the data version number stored in the backing Volumes indicate we need to upgrade
-   * something?
-   */
-  public static boolean persistentVersionNeedsUpgrade(final int accumuloPersistentVersion) {
-    return ServerConstants.NEEDS_UPGRADE.contains(accumuloPersistentVersion);
-  }
-
-  public static void monitorSwappiness(AccumuloConfiguration config) {
-    ThreadPools.createGeneralScheduledExecutorService(config).scheduleWithFixedDelay(() -> {
-      try {
-        String procFile = "/proc/sys/vm/swappiness";
-        File swappiness = new File(procFile);
-        if (swappiness.exists() && swappiness.canRead()) {
-          try (InputStream is = new FileInputStream(procFile)) {
-            byte[] buffer = new byte[10];
-            int bytes = is.read(buffer);
-            String setting = new String(buffer, 0, bytes, UTF_8);
-            setting = setting.trim();
-            if (bytes > 0 && Integer.parseInt(setting) > 10) {
-              log.warn("System swappiness setting is greater than ten ({})"
-                  + " which can cause time-sensitive operations to be delayed."
-                  + " Accumulo is time sensitive because it needs to maintain"
-                  + " distributed lock agreement.", setting);
-            }
-          }
-        }
-      } catch (Exception t) {
-        log.error("", t);
-      }
-    }, 1000, 10 * 60 * 1000, TimeUnit.MILLISECONDS);
-  }
-
-  public static void waitForZookeeperAndHdfs(ServerContext context) {
-    log.info("Attempting to talk to zookeeper");
-    while (true) {
-      try {
-        context.getZooReaderWriter().getChildren(Constants.ZROOT);
-        break;
-      } catch (InterruptedException e) {
-        // ignored
-      } catch (KeeperException ex) {
-        log.info("Waiting for accumulo to be initialized");
-        sleepUninterruptibly(1, TimeUnit.SECONDS);
-      }
-    }
-    log.info("ZooKeeper connected and initialized, attempting to talk to HDFS");
-    long sleep = 1000;
-    int unknownHostTries = 3;
-    while (true) {
-      try {
-        if (context.getVolumeManager().isReady())
-          break;
-        log.warn("Waiting for the NameNode to leave safemode");
-      } catch (IOException ex) {
-        log.warn("Unable to connect to HDFS", ex);
-      } catch (IllegalArgumentException e) {
-        /* Unwrap the UnknownHostException so we can deal with it directly */
-        if (e.getCause() instanceof UnknownHostException) {
-          if (unknownHostTries > 0) {
-            log.warn("Unable to connect to HDFS, will retry. cause: {}", e.getCause());
-            /*
-             * We need to make sure our sleep period is long enough to avoid getting a cached
-             * failure of the host lookup.
-             */
-            int ttl = AddressUtil.getAddressCacheNegativeTtl((UnknownHostException) e.getCause());
-            sleep = Math.max(sleep, (ttl + 1) * 1000L);
-          } else {
-            log.error("Unable to connect to HDFS and exceeded the maximum number of retries.", e);
-            throw e;
-          }
-          unknownHostTries--;
-        } else {
-          throw e;
-        }
-      }
-      log.info("Backing off due to failure; current sleep period is {} seconds", sleep / 1000.);
-      sleepUninterruptibly(sleep, TimeUnit.MILLISECONDS);
-      /* Back off to give transient failures more time to clear. */
-      sleep = Math.min(60 * 1000, sleep * 2);
-    }
-    log.info("Connected to HDFS");
-  }
-
-  /**
-   * Exit loudly if there are outstanding Fate operations. Since Fate serializes class names, we
-   * need to make sure there are no queued transactions from a previous version before continuing an
-   * upgrade. The status of the operations is irrelevant; those in SUCCESSFUL status cause the same
-   * problem as those just queued.
-   *
-   * Note that the Manager should not allow write access to Fate until after all upgrade steps are
-   * complete.
-   *
-   * Should be called as a guard before performing any upgrade steps, after determining that an
-   * upgrade is needed.
-   *
-   * see ACCUMULO-2519
-   */
-  public static void abortIfFateTransactions(ServerContext context) {
-    try {
-      final ReadOnlyTStore<ServerUtil> fate =
-          new ReadOnlyStore<>(new ZooStore<>(context.getZooKeeperRoot() + Constants.ZFATE,
-              context.getZooReaderWriter()));
-      if (!(fate.list().isEmpty())) {
-        throw new AccumuloException("Aborting upgrade because there are"
-            + " outstanding FATE transactions from a previous Accumulo version."
-            + " You can start the tservers and then use the shell to delete completed "
-            + " transactions. If there are uncomplete transactions, you will need to roll"
-            + " back and fix those issues. Please see the following page for more information: "
-            + " https://accumulo.apache.org/docs/2.x/troubleshooting/advanced#upgrade-issues");
-      }
-    } catch (Exception exception) {
-      log.error("Problem verifying Fate readiness", exception);
-      System.exit(1);
-    }
-  }
-}
diff --git a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
index 5ae4bfa..d6e1799 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/init/Initialize.java
@@ -92,7 +92,6 @@ import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
 import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.ServerUtil;
 import org.apache.accumulo.server.constraints.MetadataConstraints;
 import org.apache.accumulo.server.fs.VolumeChooserEnvironmentImpl;
 import org.apache.accumulo.server.fs.VolumeManager;
@@ -880,10 +879,11 @@ public class Initialize implements KeywordExecutable {
       }
     }
 
-    if (ServerUtil.getAccumuloPersistentVersion(versionPath.getFileSystem(hadoopConf), versionPath)
-        != ServerConstants.DATA_VERSION) {
-      throw new IOException("Accumulo " + Constants.VERSION + " cannot initialize data version "
-          + ServerUtil.getAccumuloPersistentVersion(fs));
+    int persistentVersion = serverConstants
+        .getAccumuloPersistentVersion(versionPath.getFileSystem(hadoopConf), versionPath);
+    if (persistentVersion != ServerConstants.DATA_VERSION) {
+      throw new IOException(
+          "Accumulo " + Constants.VERSION + " cannot initialize data version " + persistentVersion);
     }
 
     initDirs(fs, uuid, uinitializedDirs, true);
diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/ChangeSecret.java b/server/base/src/main/java/org/apache/accumulo/server/util/ChangeSecret.java
index 04c4731..139b482 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/util/ChangeSecret.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/util/ChangeSecret.java
@@ -32,8 +32,8 @@ import org.apache.accumulo.fate.zookeeper.ZooReader;
 import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.ServerUtil;
 import org.apache.accumulo.server.cli.ServerUtilOpts;
 import org.apache.accumulo.server.fs.VolumeManager;
 import org.apache.accumulo.server.fs.VolumeManagerImpl;
@@ -63,8 +63,10 @@ public class ChangeSecret {
 
   public static void main(String[] args) throws Exception {
     var siteConfig = SiteConfiguration.auto();
-    try (var fs = VolumeManagerImpl.get(siteConfig, new Configuration())) {
-      verifyHdfsWritePermission(fs);
+    var hadoopConf = new Configuration();
+    try (var fs = VolumeManagerImpl.get(siteConfig, hadoopConf)) {
+      ServerConstants serverConstants = new ServerConstants(siteConfig, hadoopConf);
+      verifyHdfsWritePermission(serverConstants, fs);
 
       Opts opts = new Opts();
       List<String> argsList = new ArrayList<>(args.length + 2);
@@ -78,7 +80,7 @@ public class ChangeSecret {
         verifyAccumuloIsDown(context, opts.oldPass);
 
         final String newInstanceId = UUID.randomUUID().toString();
-        updateHdfs(fs, newInstanceId);
+        updateHdfs(serverConstants, fs, newInstanceId);
         rewriteZooKeeperInstance(context, newInstanceId, opts.oldPass, opts.newPass);
         if (opts.oldPass != null) {
           deleteInstance(context, opts.oldPass);
@@ -160,10 +162,11 @@ public class ChangeSecret {
     new_.putPersistentData(path, newInstanceId.getBytes(UTF_8), NodeExistsPolicy.OVERWRITE);
   }
 
-  private static void updateHdfs(VolumeManager fs, String newInstanceId) throws IOException {
+  private static void updateHdfs(ServerConstants serverConstants, VolumeManager fs,
+      String newInstanceId) throws IOException {
     // Need to recreate the instanceId on all of them to keep consistency
     for (Volume v : fs.getVolumes()) {
-      final Path instanceId = ServerUtil.getInstanceIdLocation(v);
+      final Path instanceId = serverConstants.getInstanceIdLocation(v);
       if (!v.getFileSystem().delete(instanceId, true)) {
         throw new IOException("Could not recursively delete " + instanceId);
       }
@@ -176,9 +179,10 @@ public class ChangeSecret {
     }
   }
 
-  private static void verifyHdfsWritePermission(VolumeManager fs) throws Exception {
+  private static void verifyHdfsWritePermission(ServerConstants serverConstants, VolumeManager fs)
+      throws Exception {
     for (Volume v : fs.getVolumes()) {
-      final Path instanceId = ServerUtil.getInstanceIdLocation(v);
+      final Path instanceId = serverConstants.getInstanceIdLocation(v);
       FileStatus fileStatus = v.getFileSystem().getFileStatus(instanceId);
       checkHdfsAccessPermissions(fileStatus, FsAction.WRITE);
     }
diff --git a/server/base/src/test/java/org/apache/accumulo/server/ServerContextTest.java b/server/base/src/test/java/org/apache/accumulo/server/ServerContextTest.java
index 5ce9597..7621ba6 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/ServerContextTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/ServerContextTest.java
@@ -118,4 +118,10 @@ public class ServerContextTest {
     });
   }
 
+  @Test(expected = IllegalStateException.class)
+  public void testCanRun() {
+    // ensure this fails with older versions
+    ServerContext.ensureDataVersionCompatible(7);
+  }
+
 }
diff --git a/server/base/src/test/java/org/apache/accumulo/server/ServerUtilTest.java b/server/base/src/test/java/org/apache/accumulo/server/ServerUtilTest.java
deleted file mode 100644
index dc71ec4..0000000
--- a/server/base/src/test/java/org/apache/accumulo/server/ServerUtilTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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.accumulo.server;
-
-import org.junit.Test;
-
-public class ServerUtilTest {
-  @Test(expected = IllegalStateException.class)
-  public void testCanRun() {
-    // ensure this fails with older versions
-    ServerUtil.ensureDataVersionCompatible(7);
-  }
-}
diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/state/SetGoalState.java b/server/manager/src/main/java/org/apache/accumulo/manager/state/SetGoalState.java
index 9a9d27f..77406a6 100644
--- a/server/manager/src/main/java/org/apache/accumulo/manager/state/SetGoalState.java
+++ b/server/manager/src/main/java/org/apache/accumulo/manager/state/SetGoalState.java
@@ -28,7 +28,6 @@ import org.apache.accumulo.core.singletons.SingletonManager.Mode;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 import org.apache.accumulo.manager.upgrade.RenameMasterDirInZK;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.ServerUtil;
 import org.apache.accumulo.server.security.SecurityUtil;
 
 public class SetGoalState {
@@ -48,7 +47,7 @@ public class SetGoalState {
       SecurityUtil.serverLogin(siteConfig);
       var context = new ServerContext(siteConfig);
       RenameMasterDirInZK.renameMasterDirInZK(context);
-      ServerUtil.waitForZookeeperAndHdfs(context);
+      context.waitForZookeeperAndHdfs();
       context.getZooReaderWriter().putPersistentData(
           context.getZooKeeperRoot() + Constants.ZMANAGER_GOAL_STATE, args[0].getBytes(UTF_8),
           NodeExistsPolicy.OVERWRITE);
diff --git a/server/manager/src/main/java/org/apache/accumulo/manager/upgrade/UpgradeCoordinator.java b/server/manager/src/main/java/org/apache/accumulo/manager/upgrade/UpgradeCoordinator.java
index fb5f283..a5a7879 100644
--- a/server/manager/src/main/java/org/apache/accumulo/manager/upgrade/UpgradeCoordinator.java
+++ b/server/manager/src/main/java/org/apache/accumulo/manager/upgrade/UpgradeCoordinator.java
@@ -18,6 +18,7 @@
  */
 package org.apache.accumulo.manager.upgrade;
 
+import java.io.IOException;
 import java.util.Map;
 import java.util.OptionalInt;
 import java.util.concurrent.CompletableFuture;
@@ -25,12 +26,19 @@ import java.util.concurrent.Future;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.dataImpl.KeyExtent;
 import org.apache.accumulo.core.util.threads.ThreadPools;
+import org.apache.accumulo.core.volume.Volume;
+import org.apache.accumulo.fate.ReadOnlyStore;
+import org.apache.accumulo.fate.ReadOnlyTStore;
+import org.apache.accumulo.fate.ZooStore;
 import org.apache.accumulo.manager.EventCoordinator;
 import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerContext;
-import org.apache.accumulo.server.ServerUtil;
+import org.apache.accumulo.server.fs.VolumeManager;
+import org.apache.hadoop.fs.Path;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -131,8 +139,9 @@ public class UpgradeCoordinator {
         "Not currently in a suitable state to do zookeeper upgrade %s", status);
 
     try {
-      int cv = ServerUtil.getAccumuloPersistentVersion(context.getVolumeManager());
-      ServerUtil.ensureDataVersionCompatible(cv);
+      int cv = context.getServerConstants()
+          .getAccumuloPersistentVersion(context.getVolumeManager().getFirst());
+      ServerContext.ensureDataVersionCompatible(cv);
       this.currentVersion = cv;
 
       if (cv == ServerConstants.DATA_VERSION) {
@@ -141,7 +150,7 @@ public class UpgradeCoordinator {
       }
 
       if (currentVersion < ServerConstants.DATA_VERSION) {
-        ServerUtil.abortIfFateTransactions(context);
+        abortIfFateTransactions(context);
 
         for (int v = currentVersion; v < ServerConstants.DATA_VERSION; v++) {
           log.info("Upgrading Zookeeper from data version {}", v);
@@ -182,7 +191,8 @@ public class UpgradeCoordinator {
               }
 
               log.info("Updating persistent data version.");
-              ServerUtil.updateAccumuloVersion(context.getVolumeManager(), currentVersion);
+              updateAccumuloVersion(context.getServerConstants(), context.getVolumeManager(),
+                  currentVersion);
               log.info("Upgrade complete");
               setStatus(UpgradeStatus.COMPLETE, eventCoordinator);
             } catch (Exception e) {
@@ -195,7 +205,66 @@ public class UpgradeCoordinator {
     }
   }
 
+  // visible for testing
+  synchronized void updateAccumuloVersion(ServerConstants constants, VolumeManager fs,
+      int oldVersion) {
+    for (Volume volume : fs.getVolumes()) {
+      try {
+        if (constants.getAccumuloPersistentVersion(volume) == oldVersion) {
+          log.debug("Attempting to upgrade {}", volume);
+          Path dataVersionLocation = constants.getDataVersionLocation(volume);
+          fs.create(new Path(dataVersionLocation, Integer.toString(ServerConstants.DATA_VERSION)))
+              .close();
+          // TODO document failure mode & recovery if FS permissions cause above to work and below
+          // to fail ACCUMULO-2596
+          Path prevDataVersionLoc = new Path(dataVersionLocation, Integer.toString(oldVersion));
+          if (!fs.delete(prevDataVersionLoc)) {
+            throw new RuntimeException("Could not delete previous data version location ("
+                + prevDataVersionLoc + ") for " + volume);
+          }
+        }
+      } catch (IOException e) {
+        throw new RuntimeException("Unable to set accumulo version: an error occurred.", e);
+      }
+    }
+  }
+
   public UpgradeStatus getStatus() {
     return status;
   }
+
+  /**
+   * Exit loudly if there are outstanding Fate operations. Since Fate serializes class names, we
+   * need to make sure there are no queued transactions from a previous version before continuing an
+   * upgrade. The status of the operations is irrelevant; those in SUCCESSFUL status cause the same
+   * problem as those just queued.
+   *
+   * Note that the Manager should not allow write access to Fate until after all upgrade steps are
+   * complete.
+   *
+   * Should be called as a guard before performing any upgrade steps, after determining that an
+   * upgrade is needed.
+   *
+   * see ACCUMULO-2519
+   */
+  @SuppressFBWarnings(value = "DM_EXIT",
+      justification = "Want to immediately stop all manager threads on upgrade error")
+  private void abortIfFateTransactions(ServerContext context) {
+    try {
+      final ReadOnlyTStore<UpgradeCoordinator> fate =
+          new ReadOnlyStore<>(new ZooStore<>(context.getZooKeeperRoot() + Constants.ZFATE,
+              context.getZooReaderWriter()));
+      if (!(fate.list().isEmpty())) {
+        throw new AccumuloException("Aborting upgrade because there are"
+            + " outstanding FATE transactions from a previous Accumulo version."
+            + " You can start the tservers and then use the shell to delete completed "
+            + " transactions. If there are uncomplete transactions, you will need to roll"
+            + " back and fix those issues. Please see the following page for more information: "
+            + " https://accumulo.apache.org/docs/2.x/troubleshooting/advanced#upgrade-issues");
+      }
+    } catch (Exception exception) {
+      log.error("Problem verifying Fate readiness", exception);
+      System.exit(1);
+    }
+  }
 }
diff --git a/server/base/src/test/java/org/apache/accumulo/server/AccumuloTest.java b/server/manager/src/test/java/org/apache/accumulo/manager/upgrade/AccumuloTest.java
similarity index 79%
rename from server/base/src/test/java/org/apache/accumulo/server/AccumuloTest.java
rename to server/manager/src/test/java/org/apache/accumulo/manager/upgrade/AccumuloTest.java
index b845e58..4db09c0 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/AccumuloTest.java
+++ b/server/manager/src/test/java/org/apache/accumulo/manager/upgrade/AccumuloTest.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.accumulo.server;
+package org.apache.accumulo.manager.upgrade;
 
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
@@ -25,8 +25,11 @@ import static org.junit.Assert.assertEquals;
 
 import java.io.FileNotFoundException;
 
+import org.apache.accumulo.core.conf.DefaultConfiguration;
 import org.apache.accumulo.core.volume.Volume;
+import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.fs.VolumeManager;
+import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FSDataOutputStream;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
@@ -39,11 +42,13 @@ import com.google.common.collect.Sets;
 public class AccumuloTest {
   private FileSystem fs;
   private Path path;
+  private ServerConstants serverConstants;
 
   @Before
   public void setUp() {
     fs = createMock(FileSystem.class);
     path = createMock(Path.class);
+    serverConstants = new ServerConstants(DefaultConfiguration.getInstance(), new Configuration());
   }
 
   private FileStatus[] mockPersistentVersion(String s) {
@@ -63,7 +68,7 @@ public class AccumuloTest {
     expect(fs.listStatus(path)).andReturn(files);
     replay(fs);
 
-    assertEquals(42, ServerUtil.getAccumuloPersistentVersion(fs, path));
+    assertEquals(42, serverConstants.getAccumuloPersistentVersion(fs, path));
   }
 
   @Test
@@ -71,7 +76,7 @@ public class AccumuloTest {
     expect(fs.listStatus(path)).andReturn(null);
     replay(fs);
 
-    assertEquals(-1, ServerUtil.getAccumuloPersistentVersion(fs, path));
+    assertEquals(-1, serverConstants.getAccumuloPersistentVersion(fs, path));
   }
 
   @Test
@@ -79,7 +84,7 @@ public class AccumuloTest {
     expect(fs.listStatus(path)).andReturn(new FileStatus[0]);
     replay(fs);
 
-    assertEquals(-1, ServerUtil.getAccumuloPersistentVersion(fs, path));
+    assertEquals(-1, serverConstants.getAccumuloPersistentVersion(fs, path));
   }
 
   @Test(expected = RuntimeException.class)
@@ -87,7 +92,7 @@ public class AccumuloTest {
     expect(fs.listStatus(path)).andThrow(new FileNotFoundException());
     replay(fs);
 
-    assertEquals(-1, ServerUtil.getAccumuloPersistentVersion(fs, path));
+    assertEquals(-1, serverConstants.getAccumuloPersistentVersion(fs, path));
   }
 
   @Test
@@ -96,8 +101,7 @@ public class AccumuloTest {
     FileSystem fs1 = createMock(FileSystem.class);
     Path baseVersion1 = new Path("hdfs://volume1/accumulo/version");
     Path oldVersion1 = new Path("hdfs://volume1/accumulo/version/7");
-    Path newVersion1 = new Path(
-        "hdfs://volume1/accumulo/version/" + Integer.toString(ServerConstants.DATA_VERSION));
+    Path newVersion1 = new Path("hdfs://volume1/accumulo/version/" + ServerConstants.DATA_VERSION);
 
     FileStatus[] files1 = mockPersistentVersion("7");
     expect(fs1.listStatus(baseVersion1)).andReturn(files1);
@@ -114,8 +118,7 @@ public class AccumuloTest {
     FileSystem fs2 = createMock(FileSystem.class);
     Path baseVersion2 = new Path("hdfs://volume2/accumulo/version");
     Path oldVersion2 = new Path("hdfs://volume2/accumulo/version/7");
-    Path newVersion2 = new Path(
-        "hdfs://volume2/accumulo/version/" + Integer.toString(ServerConstants.DATA_VERSION));
+    Path newVersion2 = new Path("hdfs://volume2/accumulo/version/" + ServerConstants.DATA_VERSION);
 
     FileStatus[] files2 = mockPersistentVersion("7");
     expect(fs2.listStatus(baseVersion2)).andReturn(files2);
@@ -136,6 +139,9 @@ public class AccumuloTest {
     expect(vm.create(newVersion2)).andReturn(fsdos2);
     replay(vm);
 
-    ServerUtil.updateAccumuloVersion(vm, 7);
+    UpgradeCoordinator upgradeCoordinator = new UpgradeCoordinator();
+    ServerConstants constants =
+        new ServerConstants(DefaultConfiguration.getInstance(), new Configuration());
+    upgradeCoordinator.updateAccumuloVersion(constants, vm, 7);
   }
 }
diff --git a/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java b/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java
index f9c9888..7b03a7b 100644
--- a/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java
+++ b/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java
@@ -58,7 +58,6 @@ import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 import org.apache.accumulo.server.ServerContext;
 import org.apache.accumulo.server.ServerOpts;
-import org.apache.accumulo.server.ServerUtil;
 import org.apache.accumulo.server.security.SecurityUtil;
 import org.apache.accumulo.tracer.thrift.RemoteSpan;
 import org.apache.accumulo.tracer.thrift.SpanReceiver.Iface;
@@ -410,7 +409,7 @@ public class TraceServer implements Watcher, AutoCloseable {
     opts.parseArgs(app, args);
     ServerContext context = new ServerContext(opts.getSiteConfiguration());
     loginTracer(context.getConfiguration());
-    ServerUtil.init(context, app);
+    context.init(app);
     try (TraceServer server = new TraceServer(context, opts.getAddress())) {
       server.run();
     } finally {