You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@accumulo.apache.org by GitBox <gi...@apache.org> on 2022/06/02 14:43:40 UTC

[GitHub] [accumulo] EdColeman commented on a diff in pull request #2751: Add ZooKeeper info viewer utility

EdColeman commented on code in PR #2751:
URL: https://github.com/apache/accumulo/pull/2751#discussion_r888035852


##########
server/base/src/main/java/org/apache/accumulo/server/conf/util/ZooInfoViewer.java:
##########
@@ -0,0 +1,540 @@
+/*
+ * 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.conf.util;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.accumulo.core.Constants.ZINSTANCES;
+import static org.apache.accumulo.core.Constants.ZNAMESPACES;
+import static org.apache.accumulo.core.Constants.ZNAMESPACE_NAME;
+import static org.apache.accumulo.core.Constants.ZROOT;
+import static org.apache.accumulo.core.Constants.ZTABLES;
+import static org.apache.accumulo.core.Constants.ZTABLE_NAME;
+import static org.apache.accumulo.core.Constants.ZTABLE_NAMESPACE;
+
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import org.apache.accumulo.core.cli.ConfigOpts;
+import org.apache.accumulo.core.clientImpl.Namespace;
+import org.apache.accumulo.core.conf.SiteConfiguration;
+import org.apache.accumulo.core.data.InstanceId;
+import org.apache.accumulo.core.data.NamespaceId;
+import org.apache.accumulo.core.data.TableId;
+import org.apache.accumulo.fate.zookeeper.ZooReader;
+import org.apache.accumulo.fate.zookeeper.ZooReaderWriter;
+import org.apache.accumulo.fate.zookeeper.ZooUtil;
+import org.apache.accumulo.server.ServerContext;
+import org.apache.accumulo.server.conf.codec.VersionedProperties;
+import org.apache.accumulo.server.conf.store.NamespacePropKey;
+import org.apache.accumulo.server.conf.store.SystemPropKey;
+import org.apache.accumulo.server.conf.store.TablePropKey;
+import org.apache.accumulo.server.conf.store.impl.PropStoreWatcher;
+import org.apache.accumulo.server.conf.store.impl.ReadyMonitor;
+import org.apache.accumulo.server.conf.store.impl.ZooPropStore;
+import org.apache.accumulo.start.spi.KeywordExecutable;
+import org.apache.zookeeper.KeeperException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.beust.jcommander.Parameter;
+import com.google.auto.service.AutoService;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+@AutoService(KeywordExecutable.class)
+@SuppressFBWarnings(value = "PATH_TRAVERSAL_OUT",
+    justification = "app is run in same security context as user providing the filename")
+public class ZooInfoViewer implements KeywordExecutable {
+  public static final DateTimeFormatter tsFormat =
+      DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.from(ZoneOffset.UTC));
+  private static final Logger log = LoggerFactory.getLogger(ZooInfoViewer.class);
+  private final NullWatcher nullWatcher =
+      new NullWatcher(new ReadyMonitor(ZooInfoViewer.class.getSimpleName(), 20_000L));
+
+  private static final String INDENT = "  ";
+
+  /**
+   * No-op constructor - provided so ServiceLoader autoload does not consume resources.
+   */
+  public ZooInfoViewer() {}
+
+  public static void main(String[] args) throws Exception {
+    new ZooInfoViewer().execute(args);
+  }
+
+  @Override
+  public String keyword() {
+    return "zoo-info-viewer";
+  }
+
+  @Override
+  public String description() {
+    return "view Accumulo instance and property information stored in ZooKeeper";
+  }
+
+  @Override
+  public void execute(String[] args) {
+
+    ZooInfoViewer.Opts opts = new ZooInfoViewer.Opts();
+    opts.parseArgs(ZooInfoViewer.class.getName(), args);
+
+    log.info("print ids map: {}", opts.printIdMap);
+    log.info("print properties: {}", opts.printProps);
+    log.info("print instances: {}", opts.printInstanceIds);
+
+    ZooReader zooReader = new ZooReaderWriter(opts.getSiteConfiguration());
+
+    InstanceId iid = getInstanceId(zooReader, opts);
+    try {
+      generateReport(iid, opts, zooReader);
+    } catch (FileNotFoundException ex) {
+      throw new IllegalStateException("Failed to generate ZooKeeper info report", ex);
+    }
+  }
+
+  void generateReport(final InstanceId iid, final ZooInfoViewer.Opts opts,
+      final ZooReader zooReader) throws FileNotFoundException {
+
+    OutputStream outStream;
+
+    String outfile = opts.getOutfile();
+    if (outfile == null || outfile.isEmpty()) {
+      log.trace("No output file, using stdout.");
+      outStream = System.out;
+    } else {
+      outStream = new FileOutputStream(outfile);
+    }
+
+    try (PrintWriter writer =
+        new PrintWriter(new BufferedWriter(new OutputStreamWriter(outStream, UTF_8)))) {
+
+      writer.println("-----------------------------------------------");
+      writer.println("Report Time: " + tsFormat.format(Instant.now()));
+      writer.println("-----------------------------------------------");
+      if (opts.printInstanceIds) {
+        Map<String,InstanceId> instanceMap = readInstancesFromZk(zooReader);
+        printInstanceIds(instanceMap, writer);
+      }
+
+      if (opts.printIdMap) {
+        printIdMapping(iid, zooReader, writer);
+      }
+
+      if (opts.printProps) {
+        printProps(iid, zooReader, opts, writer);
+      }
+
+      writer.println("-----------------------------------------------");
+    }
+  }
+
+  /**
+   * Get the instanceID from the command line options, or from value stored in HDFS. The search
+   * order is:
+   * <ol>
+   * <li>command line: --instanceId option</li>
+   * <li>command line: --instanceName option</li>
+   * <li>HDFS</li>
+   * </ol>
+   *
+   * @param zooReader
+   *          a ZooReader
+   * @param opts
+   *          the parsed command line options.
+   * @return an instance id
+   */
+  InstanceId getInstanceId(final ZooReader zooReader, final ZooInfoViewer.Opts opts) {
+
+    if (!opts.instanceId.isEmpty()) {
+      return InstanceId.of(opts.instanceId);
+    }
+    if (!opts.instanceName.isEmpty()) {
+      Map<String,InstanceId> instanceNameToIdMap = readInstancesFromZk(zooReader);
+      String instanceName = opts.instanceName;
+      for (Map.Entry<String,InstanceId> e : instanceNameToIdMap.entrySet()) {
+        if (e.getKey().equals(instanceName)) {
+          return e.getValue();
+        }
+      }
+      throw new IllegalArgumentException(
+          "Specified instance name '" + instanceName + "' not found in ZooKeeper");
+    }
+
+    try (ServerContext context = new ServerContext(SiteConfiguration.auto())) {
+      return context.getInstanceID();
+    } catch (Exception ex) {
+      throw new IllegalArgumentException(
+          "Failed to read instance id from HDFS. Instances can be specified on the command line",
+          ex);
+    }
+  }
+
+  Map<NamespaceId,String> getNamespaceIdToNameMap(InstanceId iid, final ZooReader zooReader) {
+    SortedMap<NamespaceId,String> namespaceToName = new TreeMap<>();
+    String zooNsRoot = ZooUtil.getRoot(iid) + ZNAMESPACES;
+    try {
+      List<String> nsids = zooReader.getChildren(zooNsRoot);
+      for (String id : nsids) {
+        String path = zooNsRoot + "/" + id + ZNAMESPACE_NAME;
+        String name = new String(zooReader.getData(path), UTF_8);
+        namespaceToName.put(NamespaceId.of(id), name);
+      }
+    } catch (InterruptedException ex) {
+      Thread.currentThread().interrupt();
+      throw new IllegalStateException("Interrupted reading namespace ids from ZooKeeper", ex);
+    } catch (KeeperException ex) {
+      throw new IllegalStateException("Failed to read namespace ids from ZooKeeper", ex);
+    }
+    return namespaceToName;
+  }
+
+  private void printProps(final InstanceId iid, final ZooReader zooReader, final Opts opts,
+      final PrintWriter writer) {
+
+    if (opts.printAllProps()) {
+      log.info("all: {}", opts.printAllProps());
+    } else {
+      log.info("Filters:");
+      log.info("system: {}", opts.printSysProps());
+      log.info("namespaces: {} {}", opts.printNamespaceProps(),
+          opts.getNamespaces().size() > 0 ? opts.getNamespaces() : "");
+      log.info("tables: {} {}", opts.printTableProps(),
+          opts.getTables().size() > 0 ? opts.getTables() : "");

Review Comment:
   The multiple lines are to improve the readability - it is much easier to see the files options by type than scanning a long line. If feel that it also makes it clearer what the following output may or may not contain because of user options.
   
   The use of the logger also clearly separates the text output from the command and will not appear in an output file (if specified) this makes follow-on processing easier if that is the user's end goal.
   
   At one point, I did have one log statement print multiple lines, but that seemed odd in the output.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@accumulo.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org