From 498cbc19d0f3c8b1744d6dfa842fee7bb7888d43 Mon Sep 17 00:00:00 2001 From: arbaazkhan1 Date: Wed, 1 Jul 2026 15:39:37 -0400 Subject: [PATCH] consolidate InfoViewer and PropEditor into ZooProps --- .../server/conf/util/ZooInfoViewer.java | 19 +- .../server/conf/util/ZooPropEditor.java | 24 +- .../accumulo/server/conf/util/ZooProps.java | 208 ++++++++++++++++++ .../accumulo/test/start/KeywordStartIT.java | 2 + 4 files changed, 232 insertions(+), 21 deletions(-) create mode 100644 server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooProps.java diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooInfoViewer.java b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooInfoViewer.java index 7a592641029..d9196a2787b 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooInfoViewer.java +++ b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooInfoViewer.java @@ -93,7 +93,7 @@ public class ZooInfoViewer extends ServerKeywordExecutable { DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC)); private static final Logger log = LoggerFactory.getLogger(ZooInfoViewer.class); - private NullWatcher nullWatcher; + NullWatcher nullWatcher; private static final String INDENT = " "; @@ -108,7 +108,7 @@ public String keyword() { @Override public String description() { - return "view Accumulo instance and property information stored in ZooKeeper"; + return "[DEPRECATED - use 'zk props'] view Accumulo instance and property information stored in ZooKeeper"; } @Override @@ -118,6 +118,7 @@ public CommandGroup commandGroup() { @Override public void execute(JCommander cl, ViewerOpts opts) throws Exception { + log.warn("'zk info-infoViewer' is deprecated, use 'zk props' instead"); nullWatcher = new NullWatcher(new ReadyMonitor(ZooInfoViewer.class.getSimpleName(), 20_000L)); log.debug("print ids map: {}", opts.printIdMap); @@ -170,8 +171,8 @@ void generateReport(final ServerContext context, final ViewerOpts opts) throws E } } - private void printProps(final ServerContext context, final ViewerOpts opts, - final PrintWriter writer) throws Exception { + void printProps(final ServerContext context, final ViewerOpts opts, final PrintWriter writer) + throws Exception { var iid = context.getInstanceID(); var zooReader = context.getZooSession().asReader(); @@ -509,21 +510,21 @@ static class ViewerOpts extends ServerOpts { @Parameter(names = {"-ns", "--namespaces"}, description = "a list of namespace names to print properties, with none specified, print all. Only valid with --print-props", variableArity = true) - private List namespacesOpt = new ArrayList<>(); + public List namespacesOpt = new ArrayList<>(); @Parameter(names = {"-r", "--resource-groups"}, description = "a list of resource group names to print properties, with none specified, print all. Only valid with --print-props", variableArity = true) - private List resourceGroupOpt = new ArrayList<>(); + public List resourceGroupOpt = new ArrayList<>(); @Parameter(names = {"--system"}, description = "print the properties for the system config. Only valid with --print-props") - private boolean printSystemOpt = false; + public boolean printSystemOpt = false; @Parameter(names = {"-t", "--tables"}, description = "a list of table names to print properties, with none specified, print all. Only valid with --print-props", variableArity = true) - private List tablesOpt = new ArrayList<>(); + public List tablesOpt = new ArrayList<>(); /** * Get print all option status. @@ -568,7 +569,7 @@ String getOutfile() { } } - private static class NullWatcher extends PropStoreWatcher { + static class NullWatcher extends PropStoreWatcher { public NullWatcher(ReadyMonitor zkReadyMonitor) { super(zkReadyMonitor); } diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooPropEditor.java b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooPropEditor.java index 71455708117..270965973b5 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooPropEditor.java +++ b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooPropEditor.java @@ -65,7 +65,7 @@ public class ZooPropEditor extends ServerKeywordExecutable { private static final Logger LOG = LoggerFactory.getLogger(ZooPropEditor.class); - private NullWatcher nullWatcher; + NullWatcher nullWatcher; /** * No-op constructor - provided so ServiceLoader autoload does not consume resources. @@ -81,7 +81,7 @@ public String keyword() { @Override public String description() { - return "Emergency tool to modify properties stored in ZooKeeper without a cluster." + return "[DEPRECATED - use 'zk props'] Emergency tool to modify properties stored in ZooKeeper without a cluster." + " Prefer using the shell if it is available"; } @@ -92,6 +92,8 @@ public CommandGroup commandGroup() { @Override public void execute(JCommander cl, EditorOpts opts) throws Exception { + LOG.warn("'zk prop-editor' is deprecated, use 'zk props' instead"); + nullWatcher = new NullWatcher(new ReadyMonitor(ZooPropEditor.class.getSimpleName(), 20_000L)); var context = getServerContext(); @@ -114,8 +116,7 @@ public void execute(JCommander cl, EditorOpts opts) throws Exception { } } - private void setProperty(final ServerContext context, final PropStoreKey propKey, - final EditorOpts opts) { + void setProperty(final ServerContext context, final PropStoreKey propKey, final EditorOpts opts) { LOG.trace("set {}", propKey); if (!opts.setOpt.contains("=")) { @@ -145,7 +146,7 @@ private void setProperty(final ServerContext context, final PropStoreKey propKey } } - private void deleteProperty(final ServerContext context, final PropStoreKey propKey, + void deleteProperty(final ServerContext context, final PropStoreKey propKey, VersionedProperties versionedProperties, final EditorOpts opts) { LOG.trace("delete {} - {}", propKey, opts.deleteOpt); String p = opts.deleteOpt.trim(); @@ -163,7 +164,7 @@ private void deleteProperty(final ServerContext context, final PropStoreKey prop LOG.info("{}: deleted {}", targetName, p); } - private void printProperties(final ServerContext context, final PropStoreKey propKey, + void printProperties(final ServerContext context, final PropStoreKey propKey, final VersionedProperties props) { LOG.trace("print {}", propKey); @@ -206,7 +207,7 @@ private void printProperties(final ServerContext context, final PropStoreKey pro } } - private VersionedProperties readPropNode(final PropStoreKey propKey, final ZooReader zooReader) { + VersionedProperties readPropNode(final PropStoreKey propKey, final ZooReader zooReader) { try { return ZooPropStore.readFromZk(propKey, nullWatcher, zooReader); } catch (IOException | KeeperException | InterruptedException ex) { @@ -214,8 +215,7 @@ private VersionedProperties readPropNode(final PropStoreKey propKey, final ZooRe } } - private PropStoreKey getPropKey(final ServerContext context, - final ZooPropEditor.EditorOpts opts) { + PropStoreKey getPropKey(final ServerContext context, final ZooPropEditor.EditorOpts opts) { // either tid or table name option provided, get the table id if (!opts.tableOpt.isEmpty() || !opts.tableIdOpt.isEmpty()) { @@ -262,7 +262,7 @@ private NamespaceId getNamespaceId(final ServerContext context, () -> new IllegalArgumentException("Could not find namespace " + opts.namespaceOpt)); } - private String getDisplayName(final PropStoreKey propStoreKey, final ServerContext context) { + String getDisplayName(final PropStoreKey propStoreKey, final ServerContext context) { if (propStoreKey instanceof TablePropKey) { return context.createTableIdToQualifiedNameMap() @@ -303,7 +303,7 @@ static class EditorOpts extends ServerOpts { public String tableIdOpt = ""; @Parameter(names = {"-r", "--resource-group"}, description = "resource group name to display/set/delete properties for") - private String resourceGroupOpt = ""; + public String resourceGroupOpt = ""; @Override public void parseArgs(String programName, String[] args, Object... others) { @@ -332,7 +332,7 @@ enum CmdMode { } } - private static class NullWatcher extends PropStoreWatcher { + static class NullWatcher extends PropStoreWatcher { public NullWatcher(ReadyMonitor zkReadyMonitor) { super(zkReadyMonitor); } diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooProps.java b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooProps.java new file mode 100644 index 00000000000..aaabcf6cefc --- /dev/null +++ b/server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooProps.java @@ -0,0 +1,208 @@ +/* + * 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.server.conf.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.accumulo.core.cli.ServerOpts; +import org.apache.accumulo.server.conf.store.impl.ReadyMonitor; +import org.apache.accumulo.server.conf.util.ZooInfoViewer.ViewerOpts; +import org.apache.accumulo.server.conf.util.ZooPropEditor.EditorOpts; +import org.apache.accumulo.server.util.ServerKeywordExecutable; +import org.apache.accumulo.start.spi.CommandGroup; +import org.apache.accumulo.start.spi.CommandGroups; +import org.apache.accumulo.start.spi.KeywordExecutable; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.google.auto.service.AutoService; + +@AutoService(KeywordExecutable.class) +public class ZooProps extends ServerKeywordExecutable { + + public ZooProps() { + super(new PropsOpts()); + } + + @Override + public String keyword() { + return "props"; + } + + @Override + public String description() { + return "Inspect and edit ZooKeeper-backed Accumulo properties. " + + "Default prints properties for the resolved scope (ZooPropEditor output). " + + "Use --get for a multi-scope report with --system/--namespaces/--tables filters " + + "(ZooInfoViewer output). Use --set or --delete to mutate."; + } + + @Override + public CommandGroup commandGroup() { + return CommandGroups.ZOOKEEPER; + } + + @Override + public void execute(JCommander cl, PropsOpts opts) throws Exception { + + if (!opts.setOpt.isEmpty() && !opts.deleteOpt.isEmpty()) { + throw new IllegalArgumentException("Cannot use --set and --delete together."); + } + + if (!opts.setOpt.isEmpty()) { + ZooPropEditor editor = buildEditor(); + var context = getServerContext(); + EditorOpts editorOpts = toEditorOpts(opts); + editorOpts.setOpt = opts.setOpt; + editor.setProperty(context, editor.getPropKey(context, editorOpts), editorOpts); + + } else if (!opts.deleteOpt.isEmpty()) { + ZooPropEditor editor = buildEditor(); + var context = getServerContext(); + var zrw = context.getZooSession().asReaderWriter(); + EditorOpts editorOpts = toEditorOpts(opts); + editorOpts.deleteOpt = opts.deleteOpt; + var propKey = editor.getPropKey(context, editorOpts); + editor.deleteProperty(context, propKey, editor.readPropNode(propKey, zrw), editorOpts); + + } else if (opts.getOpt) { + ZooInfoViewer viewer = buildViewer(); + ViewerOpts viewerOpts = toViewerOpts(opts); + viewerOpts.printProps = true; + + // TODO + // Add PR #6419 Json hook + + viewer.generateReport(getServerContext(), viewerOpts); + + } else { + ZooPropEditor editor = buildEditor(); + var context = getServerContext(); + var zrw = context.getZooSession().asReaderWriter(); + EditorOpts editorOpts = toEditorOpts(opts); + var propKey = editor.getPropKey(context, editorOpts); + editor.printProperties(context, propKey, editor.readPropNode(propKey, zrw)); + + // TODO + // Add PR #6419 Json hook + + } + } + + private ZooPropEditor buildEditor() { + ZooPropEditor editor = new ZooPropEditor(); + editor.nullWatcher = new ZooPropEditor.NullWatcher( + new ReadyMonitor(ZooPropEditor.class.getSimpleName(), 20_000L)); + return editor; + } + + private ZooInfoViewer buildViewer() { + ZooInfoViewer viewer = new ZooInfoViewer(); + viewer.nullWatcher = new ZooInfoViewer.NullWatcher( + new ReadyMonitor(ZooInfoViewer.class.getSimpleName(), 20_000L)); + return viewer; + } + + private EditorOpts toEditorOpts(PropsOpts opts) { + EditorOpts e = new EditorOpts(); + e.tableOpt = opts.tableOpt; + e.tableIdOpt = opts.tableIdOpt; + e.namespaceOpt = opts.namespaceOpt; + e.namespaceIdOpt = opts.namespaceIdOpt; + e.resourceGroupOpt = opts.resourceGroupOpt.isEmpty() ? "" : opts.resourceGroupOpt.get(0); + return e; + } + + private ViewerOpts toViewerOpts(PropsOpts opts) { + ViewerOpts v = new ViewerOpts(); + v.outfile = opts.outfile; + v.printSystemOpt = opts.systemOpt; + v.tablesOpt.addAll(opts.tablesOpt); + v.namespacesOpt.addAll(opts.namespacesOpt); + v.resourceGroupOpt.addAll(opts.resourceGroupOpt); + return v; + } + + static class PropsOpts extends ServerOpts { + @Parameter(names = {"-s", "--set"}, description = "set a property") + String setOpt = ""; + + @Parameter(names = {"-d", "--delete"}, description = "delete a property") + String deleteOpt = ""; + + @Parameter(names = {"-t", "--table"}, + description = "table to display/set/delete properties for") + String tableOpt = ""; + + @Parameter(names = {"-tid", "--table-id"}, + description = "table id to display/set/delete properties for") + String tableIdOpt = ""; + + @Parameter(names = {"-ns", "--namespace"}, + description = "namespace to display/set/delete properties for") + String namespaceOpt = ""; + + @Parameter(names = {"-nid", "--namespace-id"}, + description = "namespace id to display/set/delete properties for") + String namespaceIdOpt = ""; + + @Parameter(names = {"-r", "--resource-group"}, + description = "resource group name to display/set/delete properties for", + variableArity = true) + List resourceGroupOpt = new ArrayList<>(); + + @Parameter(names = {"--get"}, + description = "print a multi-scope property report (ZooInfoViewer output). " + + "Enables --system, --namespaces, and --tables filter flags.") + boolean getOpt = false; + + @Parameter(names = {"--system"}, + description = "print the properties for the system config. Only valid with --get") + boolean systemOpt = false; + + @Parameter(names = {"--namespaces"}, + description = "a list of namespace names to print properties, with none specified, print all. Only valid with --get", + variableArity = true) + List namespacesOpt = new ArrayList<>(); + + @Parameter(names = {"--tables"}, + description = "a list of table names to print properties. Only valid with --get", + variableArity = true) + List tablesOpt = new ArrayList<>(); + + @Parameter(names = {"--outfile"}, + description = "Write the output to a file, if the file exists will not be overwritten.") + String outfile = ""; + + @Override + public void parseArgs(String programName, String[] args, Object... others) { + super.parseArgs(programName, args, others); + if (!setOpt.isEmpty() && !deleteOpt.isEmpty()) { + throw new IllegalArgumentException("Cannot use --set and --delete in one command"); + } + if ((!systemOpt || !namespacesOpt.isEmpty() || !tablesOpt.isEmpty()) && !getOpt + && setOpt.isEmpty() && deleteOpt.isEmpty()) { + if (!namespacesOpt.isEmpty() || !tablesOpt.isEmpty()) { + throw new IllegalArgumentException("--namespaces and --tables are only valid with --get"); + } + } + } + } +} diff --git a/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java b/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java index e97eeb09719..aa4e766a3c1 100644 --- a/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java +++ b/test/src/main/java/org/apache/accumulo/test/start/KeywordStartIT.java @@ -62,6 +62,7 @@ import org.apache.accumulo.server.conf.util.ImportConfigCommand; import org.apache.accumulo.server.conf.util.ZooInfoViewer; import org.apache.accumulo.server.conf.util.ZooPropEditor; +import org.apache.accumulo.server.conf.util.ZooProps; import org.apache.accumulo.server.init.Initialize; import org.apache.accumulo.server.util.CancelCompaction; import org.apache.accumulo.server.util.DumpZookeeper; @@ -254,6 +255,7 @@ public void testExpectedClasses() { expectSet.add(new CommandInfo(CommandGroups.ZOOKEEPER, "prop-editor", ZooPropEditor.class)); expectSet.add(new CommandInfo(CommandGroups.ZOOKEEPER, "zap", ZooZap.class)); expectSet.add(new CommandInfo(CommandGroups.ZOOKEEPER, "cli", ZooKeeperMain.class)); + expectSet.add(new CommandInfo(CommandGroups.ZOOKEEPER, "props", ZooProps.class)); Map> actualExecutables = getKeywordExecutables(); SortedSet actualSet = new TreeSet<>();