![JAR search and dependency download from the Maven repository](/logo.png)
com.unboundid.ldap.sdk.unboundidds.tools.CollectSupportData Maven / Gradle / Ivy
/*
* Copyright 2020 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2020 Ping Identity Corporation
*
* Licensed 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.
*/
/*
* Copyright (C) 2020 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk.unboundidds.tools;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.Version;
import com.unboundid.ldap.sdk.unboundidds.controls.NoOpRequestControl;
import com.unboundid.ldap.sdk.unboundidds.extensions.
CollectSupportDataExtendedRequest;
import com.unboundid.ldap.sdk.unboundidds.extensions.
CollectSupportDataExtendedRequestProperties;
import com.unboundid.ldap.sdk.unboundidds.extensions.
CollectSupportDataExtendedResult;
import com.unboundid.ldap.sdk.unboundidds.extensions.
DurationCollectSupportDataLogCaptureWindow;
import com.unboundid.ldap.sdk.unboundidds.extensions.
HeadAndTailSizeCollectSupportDataLogCaptureWindow;
import com.unboundid.ldap.sdk.unboundidds.extensions.
StartAdministrativeSessionExtendedRequest;
import com.unboundid.ldap.sdk.unboundidds.extensions.
StartAdministrativeSessionPostConnectProcessor;
import com.unboundid.ldap.sdk.unboundidds.extensions.
TimeWindowCollectSupportDataLogCaptureWindow;
import com.unboundid.ldap.sdk.unboundidds.tasks.CollectSupportDataSecurityLevel;
import com.unboundid.util.Base64;
import com.unboundid.util.Debug;
import com.unboundid.util.LDAPCommandLineTool;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.ObjectPair;
import com.unboundid.util.PasswordReader;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.args.Argument;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;
import com.unboundid.util.args.BooleanArgument;
import com.unboundid.util.args.DurationArgument;
import com.unboundid.util.args.FileArgument;
import com.unboundid.util.args.IntegerArgument;
import com.unboundid.util.args.StringArgument;
import com.unboundid.util.args.TimestampArgument;
import static com.unboundid.ldap.sdk.unboundidds.tools.ToolMessages.*;
/**
* This class provides a command-line tool that may be used to invoke the
* collect-support-data utility in the Ping Identity Directory Server and
* related server products.
*
*
* NOTE: This class, and other classes within the
* {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
* supported for use against Ping Identity, UnboundID, and
* Nokia/Alcatel-Lucent 8661 server products. These classes provide support
* for proprietary functionality or for external specifications that are not
* considered stable or mature enough to be guaranteed to work in an
* interoperable way with other types of LDAP servers.
*
*
* Note that this is a client-side wrapper for the application. While it may
* be used to invoke the tool against a remote server using the
* {@link CollectSupportDataExtendedRequest}, it does not include direct support
* for invoking the tool against a local instance. That will be accomplished
* indirectly by invoking the server-side version of the tool via reflection.
*/
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class CollectSupportData
extends LDAPCommandLineTool
{
/**
* The column at which to wrap long lines.
*/
private static final int WRAP_COLUMN = StaticUtils.TERMINAL_WIDTH_COLUMNS - 1;
/**
* The Ping Identity Directory Server's default access log timestamp format
* when configured to use millisecond precision.
*/
@NotNull static final String SERVER_LOG_TIMESTAMP_FORMAT_WITH_MILLIS =
"'['dd/MMM/yyyy:HH:mm:ss.SSS Z']'";
/**
* The Ping Identity Directory Server's default access log timestamp format
* when configured to use second precision.
*/
@NotNull static final String SERVER_LOG_TIMESTAMP_FORMAT_WITHOUT_MILLIS =
"'['dd/MMM/yyyy:HH:mm:ss Z']'";
/**
* The fully-qualified name of the class in the server codebase that will be
* invoked to perform collect-support-data processing when the
* --useRemoteServer argument is not provided.
*/
@NotNull private static final String SERVER_CSD_TOOL_CLASS =
"com.unboundid.directory.server.tools.CollectSupportData";
// The completion message for this tool, if available.
@NotNull private final AtomicReference toolCompletionMessage;
// The command-line arguments supported by this tool.
@Nullable private ArgumentParser parser;
@Nullable private BooleanArgument archiveExtensionSourceArg;
@Nullable private BooleanArgument collectExpensiveDataArg;
@Nullable private BooleanArgument collectReplicationStateDumpArg;
@Nullable private BooleanArgument dryRunArg;
@Nullable private BooleanArgument encryptArg;
@Nullable private BooleanArgument generatePassphraseArg;
@Nullable private BooleanArgument includeBinaryFilesArg;
@Nullable private BooleanArgument noLDAPArg;
@Nullable private BooleanArgument noPromptArg;
@Nullable private BooleanArgument scriptFriendlyArg;
@Nullable private BooleanArgument sequentialArg;
@Nullable private BooleanArgument useAdministrativeSessionArg;
@Nullable private BooleanArgument useRemoteServerArg;
@Nullable private DurationArgument logDurationArg;
@Nullable private FileArgument decryptArg;
@Nullable private FileArgument outputPathArg;
@Nullable private FileArgument passphraseFileArg;
@Nullable private IntegerArgument jstackCountArg;
@Nullable private IntegerArgument logFileHeadCollectionSizeKBArg;
@Nullable private IntegerArgument logFileTailCollectionSizeKBArg;
@Nullable private IntegerArgument reportCountArg;
@Nullable private IntegerArgument reportIntervalSecondsArg;
@Nullable private IntegerArgument pidArg;
@Nullable private IntegerArgument proxyToServerPortArg;
@Nullable private StringArgument commentArg;
@Nullable private StringArgument proxyToServerAddressArg;
@Nullable private StringArgument securityLevelArg;
@Nullable private StringArgument logTimeRangeArg;
/**
* Invokes this tool with the provided set of command-line arguments. The
* JVM's default standard output and standard error streams will be used.
*
* @param args The set of command-line arguments provided to this program.
* It must not be {@code null} but may be empty.
*/
public static void main(@NotNull final String... args)
{
final ResultCode resultCode = main(System.out, System.err, args);
if ((resultCode != ResultCode.SUCCESS) &&
(resultCode != ResultCode.NO_OPERATION))
{
System.exit(resultCode.intValue());
}
}
/**
* Invokes this tool with the provided set of command-line arguments, using
* the given output and error streams.
*
* @param out The output stream to use for standard output. It may be
* {@code null} if standard output should be suppressed.
* @param err The output stream to use for standard error. It may be
* {@code null} if standard error should be suppressed.
* @param args The set of command-line arguments provided to this program.
* It must not be {@code null} but may be empty.
*
* @return A result code indicating the final status of the processing that
* was performed. A result code of {@link ResultCode#SUCCESS}
* indicates that all processing was successful. A result code of
* {@link ResultCode#NO_OPERATION} indicates that it is likely that
* processing would have been successful if the --dryRun argument
* had not been provided. Any other result code indicates that the
* processing did not complete successfully.
*/
@NotNull()
public static ResultCode main(@Nullable final OutputStream out,
@Nullable final OutputStream err,
@NotNull final String... args)
{
final CollectSupportData tool = new CollectSupportData(out, err);
return tool.runTool(args);
}
/**
* Creates a new instance of this tool that will use the provided streams for
* standard output and standard error.
*
* @param out The output stream to use for standard output. It may be
* {@code null} if standard output should be suppressed.
* @param err The output stream to use for standard error. It may be
* {@code null} if standard error should be suppressed.
*/
public CollectSupportData(@Nullable final OutputStream out,
@Nullable final OutputStream err)
{
super(out, err);
toolCompletionMessage = new AtomicReference<>();
parser = null;
archiveExtensionSourceArg = null;
collectExpensiveDataArg = null;
collectReplicationStateDumpArg = null;
dryRunArg = null;
encryptArg = null;
generatePassphraseArg = null;
includeBinaryFilesArg = null;
noLDAPArg = null;
noPromptArg = null;
scriptFriendlyArg = null;
sequentialArg = null;
useRemoteServerArg = null;
logDurationArg = null;
logFileHeadCollectionSizeKBArg = null;
logFileTailCollectionSizeKBArg = null;
jstackCountArg = null;
outputPathArg = null;
reportCountArg = null;
decryptArg = null;
passphraseFileArg = null;
reportIntervalSecondsArg = null;
pidArg = null;
proxyToServerPortArg = null;
commentArg = null;
logTimeRangeArg = null;
proxyToServerAddressArg = null;
securityLevelArg = null;
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getToolName()
{
return "collect-support-data";
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getToolDescription()
{
return INFO_CSD_TOOL_DESCRIPTION_1.get();
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public List getAdditionalDescriptionParagraphs()
{
return Collections.singletonList(INFO_CSD_TOOL_DESCRIPTION_2.get());
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getToolVersion()
{
return Version.NUMERIC_VERSION_STRING;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean supportsInteractiveMode()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean defaultsToInteractiveMode()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override()
public boolean supportsPropertiesFile()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean defaultToPromptForBindPassword()
{
if ((noPromptArg != null) && noPromptArg.isPresent())
{
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean includeAlternateLongIdentifiers()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean supportsSSLDebugging()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
protected boolean logToolInvocationByDefault()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override()
@Nullable()
protected String getToolCompletionMessage()
{
return toolCompletionMessage.get();
}
/**
* {@inheritDoc}
*/
@Override()
public void addNonLDAPArguments(@NotNull final ArgumentParser parser)
throws ArgumentException
{
this.parser = parser;
// Output-related arguments.
outputPathArg = new FileArgument(null, "outputPath", false, 1, null,
INFO_CSD_ARG_DESC_OUTPUT_PATH.get(), false, true, false, false);
outputPathArg.addLongIdentifier("output-path", true);
outputPathArg.addLongIdentifier("outputFile", true);
outputPathArg.addLongIdentifier("output-file", true);
outputPathArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_OUTPUT.get());
parser.addArgument(outputPathArg);
encryptArg = new BooleanArgument(null, "encrypt", 1,
INFO_CSD_ARG_DESC_ENCRYPT.get());
encryptArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_OUTPUT.get());
parser.addArgument(encryptArg);
passphraseFileArg = new FileArgument(null, "passphraseFile", false, 1,
null, INFO_CSD_ARG_DESC_PASSPHRASE_FILE.get(), false, true, true,
false);
passphraseFileArg.addLongIdentifier("passphrase-file", true);
passphraseFileArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_OUTPUT.get());
parser.addArgument(passphraseFileArg);
generatePassphraseArg = new BooleanArgument(null, "generatePassphrase", 1,
INFO_CSD_ARG_DESC_GENERATE_PASSPHRASE.get());
generatePassphraseArg.addLongIdentifier("generate-passphrase", true);
generatePassphraseArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_OUTPUT.get());
parser.addArgument(generatePassphraseArg);
decryptArg = new FileArgument(null, "decrypt", false, 1, null,
INFO_CSD_ARG_DESC_DECRYPT.get(), false, true, true, false);
decryptArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_OUTPUT.get());
parser.addArgument(decryptArg);
// Collection-related arguments.
collectExpensiveDataArg = new BooleanArgument(null, "collectExpensiveData",
1, INFO_CSD_ARG_DESC_COLLECT_EXPENSIVE_DATA.get());
collectExpensiveDataArg.addLongIdentifier("collect-expensive-data", true);
collectExpensiveDataArg.addLongIdentifier("includeExpensiveData", true);
collectExpensiveDataArg.addLongIdentifier("include-expensive-data", true);
collectExpensiveDataArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(collectExpensiveDataArg);
collectReplicationStateDumpArg = new BooleanArgument(null,
"collectReplicationStateDump", 1,
INFO_CSD_ARG_DESC_COLLECT_REPL_STATE.get());
collectReplicationStateDumpArg.addLongIdentifier(
"collect-replication-state-dump", true);
collectReplicationStateDumpArg.addLongIdentifier(
"collectReplicationState", true);
collectReplicationStateDumpArg.addLongIdentifier(
"collect-replication-state", true);
collectReplicationStateDumpArg.addLongIdentifier(
"includeReplicationStateDump", true);
collectReplicationStateDumpArg.addLongIdentifier(
"include-replication-state-dump", true);
collectReplicationStateDumpArg.addLongIdentifier(
"includeReplicationState", true);
collectReplicationStateDumpArg.addLongIdentifier(
"include-replication-state", true);
collectReplicationStateDumpArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(collectReplicationStateDumpArg);
includeBinaryFilesArg = new BooleanArgument(null, "includeBinaryFiles", 1,
INFO_CSD_ARG_DESC_INCLUDE_BINARY_FILES.get());
includeBinaryFilesArg.addLongIdentifier("include-binary-files", true);
includeBinaryFilesArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(includeBinaryFilesArg);
archiveExtensionSourceArg = new BooleanArgument(null,
"archiveExtensionSource", 1,
INFO_CSD_ARG_DESC_ARCHIVE_EXTENSION_SOURCE.get());
archiveExtensionSourceArg.addLongIdentifier("archive-extension-source",
true);
archiveExtensionSourceArg.addLongIdentifier("includeExtensionSource", true);
archiveExtensionSourceArg.addLongIdentifier("include-extension-source",
true);
archiveExtensionSourceArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(archiveExtensionSourceArg);
sequentialArg = new BooleanArgument(null, "sequential", 1,
INFO_CSD_ARG_DESC_SEQUENTIAL.get());
sequentialArg.addLongIdentifier("sequentialMode", true);
sequentialArg.addLongIdentifier("sequential-mode", true);
sequentialArg.addLongIdentifier("useSequentialMode", true);
sequentialArg.addLongIdentifier("use-sequential-mode", true);
sequentialArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(sequentialArg);
securityLevelArg = new StringArgument(null, "securityLevel", false, 1,
INFO_CSD_ARG_PLACEHOLDER_SECURITY_LEVEL.get(),
INFO_CSD_ARG_DESC_SECURITY_LEVEL.get(),
StaticUtils.setOf(
CollectSupportDataSecurityLevel.NONE.getName(),
CollectSupportDataSecurityLevel.OBSCURE_SECRETS.getName(),
CollectSupportDataSecurityLevel.MAXIMUM.getName()));
securityLevelArg.addLongIdentifier("security-level", true);
securityLevelArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(securityLevelArg);
jstackCountArg = new IntegerArgument(null, "jstackCount", false, 1,
INFO_CSD_ARG_PLACEHOLDER_COUNT.get(),
INFO_CSD_ARG_DESC_JSTACK_COUNT.get(), 0, Integer.MAX_VALUE);
jstackCountArg.addLongIdentifier("jstack-count", true);
jstackCountArg.addLongIdentifier("maxJstacks", true);
jstackCountArg.addLongIdentifier("max-jstacks", true);
jstackCountArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(jstackCountArg);
reportCountArg = new IntegerArgument(null, "reportCount", false, 1,
INFO_CSD_ARG_PLACEHOLDER_COUNT.get(),
INFO_CSD_ARG_DESC_REPORT_COUNT.get(), 0, Integer.MAX_VALUE);
reportCountArg.addLongIdentifier("report-count", true);
reportCountArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(reportCountArg);
reportIntervalSecondsArg = new IntegerArgument(null,
"reportIntervalSeconds", false, 1,
INFO_CSD_ARG_PLACEHOLDER_SECONDS.get(),
INFO_CSD_ARG_DESC_REPORT_INTERVAL_SECONDS.get(), 1,
Integer.MAX_VALUE);
reportIntervalSecondsArg.addLongIdentifier("report-interval-seconds", true);
reportIntervalSecondsArg.addLongIdentifier("reportInterval", true);
reportIntervalSecondsArg.addLongIdentifier("report-interval", true);
reportIntervalSecondsArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(reportIntervalSecondsArg);
logTimeRangeArg = new StringArgument(null, "logTimeRange", false, 1,
INFO_CSD_ARG_PLACEHOLDER_TIME_RANGE.get(),
INFO_CSD_ARG_DESC_TIME_RANGE.get());
logTimeRangeArg.addLongIdentifier("log-time-range", true);
logTimeRangeArg.addLongIdentifier("timeRange", true);
logTimeRangeArg.addLongIdentifier("time-range", true);
logTimeRangeArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(logTimeRangeArg);
logDurationArg = new DurationArgument(null, "logDuration", false, null,
INFO_CSD_ARG_DESC_DURATION.get());
logDurationArg.addLongIdentifier("log-duration", true);
logDurationArg.addLongIdentifier("duration", true);
logDurationArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(logDurationArg);
logFileHeadCollectionSizeKBArg = new IntegerArgument(null,
"logFileHeadCollectionSizeKB", false, 1,
INFO_CSD_ARG_PLACEHOLDER_SIZE_KB.get(),
INFO_CSD_ARG_DESC_LOG_HEAD_SIZE_KB.get(), 0, Integer.MAX_VALUE);
logFileHeadCollectionSizeKBArg.addLongIdentifier(
"log-file-head-collection-size-kb", true);
logFileHeadCollectionSizeKBArg.addLongIdentifier("logFileHeadSizeKB", true);
logFileHeadCollectionSizeKBArg.addLongIdentifier("log-file-head-size-kb",
true);
logFileHeadCollectionSizeKBArg.addLongIdentifier("logHeadCollectionSizeKB",
true);
logFileHeadCollectionSizeKBArg.addLongIdentifier(
"log-head-collection-size-kb", true);
logFileHeadCollectionSizeKBArg.addLongIdentifier("logHeadSizeKB", true);
logFileHeadCollectionSizeKBArg.addLongIdentifier("log-head-size-kb", true);
logFileHeadCollectionSizeKBArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(logFileHeadCollectionSizeKBArg);
logFileTailCollectionSizeKBArg = new IntegerArgument(null,
"logFileTailCollectionSizeKB", false, 1,
INFO_CSD_ARG_PLACEHOLDER_SIZE_KB.get(),
INFO_CSD_ARG_DESC_LOG_TAIL_SIZE_KB.get(), 0, Integer.MAX_VALUE);
logFileTailCollectionSizeKBArg.addLongIdentifier(
"log-file-tail-collection-size-kb", true);
logFileTailCollectionSizeKBArg.addLongIdentifier("logFileTailSizeKB", true);
logFileTailCollectionSizeKBArg.addLongIdentifier("log-file-tail-size-kb",
true);
logFileTailCollectionSizeKBArg.addLongIdentifier("logTailCollectionSizeKB",
true);
logFileTailCollectionSizeKBArg.addLongIdentifier(
"log-tail-collection-size-kb", true);
logFileTailCollectionSizeKBArg.addLongIdentifier("logTailSizeKB", true);
logFileTailCollectionSizeKBArg.addLongIdentifier("log-tail-size-kb", true);
logFileTailCollectionSizeKBArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(logFileTailCollectionSizeKBArg);
pidArg = new IntegerArgument(null, "pid", false, 0,
INFO_CSD_ARG_PLACEHOLDER_PID.get(), INFO_CSD_ARG_DESC_PID.get());
pidArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(pidArg);
commentArg = new StringArgument(null, "comment", false, 1, null,
INFO_CSD_ARG_DESC_COMMENT.get());
commentArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COLLECTION.get());
parser.addArgument(commentArg);
// Communication-related arguments.
useRemoteServerArg = new BooleanArgument(null, "useRemoteServer", 1,
INFO_CSD_ARG_DEC_USE_REMOTE_SERVER.get());
useRemoteServerArg.addLongIdentifier("use-remote-server", true);
useRemoteServerArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COMMUNICATION.get());
parser.addArgument(useRemoteServerArg);
useAdministrativeSessionArg = new BooleanArgument(null,
"useAdministrativeSession", 1,
INFO_CSD_ARG_DESC_USE_ADMIN_SESSION.get());
useAdministrativeSessionArg.addLongIdentifier("use-administrative-session",
true);
useAdministrativeSessionArg.addLongIdentifier("useAdminSession", true);
useAdministrativeSessionArg.addLongIdentifier("use-admin-session",
true);
useAdministrativeSessionArg.addLongIdentifier("administrativeSession",
true);
useAdministrativeSessionArg.addLongIdentifier("administrative-session",
true);
useAdministrativeSessionArg.addLongIdentifier("adminSession", true);
useAdministrativeSessionArg.addLongIdentifier("admin-session", true);
useAdministrativeSessionArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COMMUNICATION.get());
parser.addArgument(useAdministrativeSessionArg);
proxyToServerAddressArg = new StringArgument(null, "proxyToServerAddress",
false, 1, INFO_CSD_ARG_PLACEHOLDER_ADDRESS.get(),
INFO_CSD_ARG_DESC_PROXY_TO_ADDRESS.get());
proxyToServerAddressArg.addLongIdentifier("proxy-to-server-address", true);
proxyToServerAddressArg.addLongIdentifier("proxyToAddress", true);
proxyToServerAddressArg.addLongIdentifier("proxy-to-address", true);
proxyToServerAddressArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COMMUNICATION.get());
parser.addArgument(proxyToServerAddressArg);
proxyToServerPortArg = new IntegerArgument(null, "proxyToServerPort", false,
1, INFO_CSD_ARG_PLACEHOLDER_PORT.get(),
INFO_CSD_ARG_DESC_PROXY_TO_PORT.get(), 1, 65535);
proxyToServerPortArg.addLongIdentifier("proxy-to-server-port", true);
proxyToServerPortArg.addLongIdentifier("proxyToPort", true);
proxyToServerPortArg.addLongIdentifier("proxy-to-port", true);
proxyToServerPortArg.setArgumentGroupName(
INFO_CSD_ARG_GROUP_COMMUNICATION.get());
parser.addArgument(proxyToServerPortArg);
noLDAPArg = new BooleanArgument(null, "noLDAP", 1,
INFO_CSD_ARG_DESC_NO_LDAP.get());
noLDAPArg.addLongIdentifier("no-ldap", true);
noLDAPArg.setArgumentGroupName(INFO_CSD_ARG_GROUP_COMMUNICATION.get());
parser.addArgument(noLDAPArg);
// Other arguments.
noPromptArg = new BooleanArgument('n', "noPrompt", 1,
INFO_CSD_ARG_DESC_NO_PROMPT.get());
noPromptArg.addLongIdentifier("no-prompt", true);
parser.addArgument(noPromptArg);
dryRunArg = new BooleanArgument(null, "dryRun", 1,
INFO_CSD_ARG_DESC_DRY_RUN.get());
dryRunArg.addLongIdentifier("dry-run", true);
dryRunArg.addLongIdentifier("noOperation", true);
dryRunArg.addLongIdentifier("no-operation", true);
dryRunArg.addLongIdentifier("noOp", true);
dryRunArg.addLongIdentifier("no-op", true);
parser.addArgument(dryRunArg);
scriptFriendlyArg = new BooleanArgument(null, "scriptFriendly", 1,
INFO_CSD_ARG_DESC_SCRIPT_FRIENDLY.get());
scriptFriendlyArg.addLongIdentifier("script-friendly", true);
scriptFriendlyArg.setHidden(true);
parser.addArgument(scriptFriendlyArg);
// If the --useRemoteServer argument is provided, then none of the --pid,
// --decrypt, --noLDAP, or --scriptFriendly arguments may be given.
parser.addExclusiveArgumentSet(useRemoteServerArg, pidArg);
parser.addExclusiveArgumentSet(useRemoteServerArg, decryptArg);
parser.addExclusiveArgumentSet(useRemoteServerArg, noLDAPArg);
parser.addExclusiveArgumentSet(useRemoteServerArg, scriptFriendlyArg);
// The --useAdministrativeSession argument can only be provided if the
// --useRemoteServer argument is also given.
parser.addDependentArgumentSet(useAdministrativeSessionArg,
useRemoteServerArg);
// If the --proxyToServerAddress or --proxyToServerPort argument is given,
// then the other must be provided as well.
parser.addMutuallyDependentArgumentSet(proxyToServerAddressArg,
proxyToServerPortArg);
// The --proxyToServerAddress and --proxyToServerPort arguments can only
// be used if the --useRemoteServer argument is given.
parser.addDependentArgumentSet(proxyToServerAddressArg, useRemoteServerArg);
parser.addDependentArgumentSet(proxyToServerPortArg, useRemoteServerArg);
// The --logTimeRange and --logDuration arguments cannot be used together.
parser.addExclusiveArgumentSet(logTimeRangeArg, logDurationArg);
// Neither the --logFileHeadCollectionSizeKB argument nor the
// --logFileTailCollectionSizeKB argument can be used in conjunction with
// either the --logTimeRange or --logDuration argument.
parser.addExclusiveArgumentSet(logFileHeadCollectionSizeKBArg,
logTimeRangeArg, logDurationArg);
parser.addExclusiveArgumentSet(logFileTailCollectionSizeKBArg,
logTimeRangeArg, logDurationArg);
// The --generatePassphrase argument can only be used if both the
// --encrypt and --passphraseFile arguments are provided.
parser.addDependentArgumentSet(generatePassphraseArg, encryptArg);
parser.addDependentArgumentSet(generatePassphraseArg, passphraseFileArg);
// The --encrypt and --decrypt arguments cannot be used together.
parser.addExclusiveArgumentSet(encryptArg, decryptArg);
// There are several arguments that the LDAP SDK's LDAP command-line tool
// framework offers that the server-side version of the framework does not
// provide. Those arguments can only be used in conjunction with the
// --useRemoteServer argument.
for (final String argumentIdentifier :
Arrays.asList("promptForBindPassword", "promptForKeyStorePassword",
"keyStoreFormat", "promptForTrustStorePassword",
"trustStoreFormat", "enableSSLDebugging", "useSASLExternal"))
{
final Argument arg = parser.getNamedArgument(argumentIdentifier);
parser.addDependentArgumentSet(arg, useRemoteServerArg);
}
}
/**
* {@inheritDoc}
*/
@Override()
public void doExtendedNonLDAPArgumentValidation()
throws ArgumentException
{
// If the --logTimeRange argument was provided, then make sure we can
// parse each of the values and that the end time is greater than or equal
// to the start time.
if (logTimeRangeArg.isPresent())
{
try
{
parseTimeRange(logTimeRangeArg.getValue(),
useRemoteServerArg.isPresent());
}
catch (final LDAPException e)
{
Debug.debugException(e);
toolCompletionMessage.set(e.getMessage());
throw new ArgumentException(e.getMessage(), e);
}
}
// If the --passphraseFile argument was provided without the
// --generatePassphrase argument, then make sure the file exists.
if (passphraseFileArg.isPresent() && (! generatePassphraseArg.isPresent()))
{
final File passphraseFile = passphraseFileArg.getValue();
if (! passphraseFile.exists())
{
final String message =ERR_CSD_PASSPHRASE_FILE_MISSING.get(
passphraseFile.getAbsolutePath());
toolCompletionMessage.set(message);
throw new ArgumentException(message);
}
}
// If either the --encrypt or --decrypt argument is provided in conjunction
// with the --noPrompt argument, then the --passphraseFile argument must
// also have been provided.
if (noPromptArg.isPresent() &&
(encryptArg.isPresent() || decryptArg.isPresent()) &&
(! passphraseFileArg.isPresent()))
{
final String message = ERR_CSD_NO_PASSPHRASE_WITH_NO_PROMPT.get();
toolCompletionMessage.set(message);
throw new ArgumentException(message);
}
}
/**
* Parses the provided string as a time range. If both start and end time
* values are provided, then they must be separated by a comma; otherwise,
* there must only be a start time value. Each timestamp must be in either
* the generalized time format or the Ping Identity Directory Server's default
* access log format (with or without millisecond precision).
*
* @param timeRangeStr The string to be parsed as a time range. It must not
* be {@code null}.
* @param strict Indicates whether to require strict compliance with
* the timestamp format. This should be {@code true}
* when the useRemoteServer argument was provided, and
* {@code false} otherwise.
*
* @return An object pair in which the first value is the start time for
* the range and the second value is the end time for the range. The
* first element will always be non-{@code null}, but the second
* element may be {@code null} if the time range did not specify an
* end time. The entire return value may be {@code null} if the
* time range string could not be parsed and {@code strict} is
* {@code false}.
*
* @throws LDAPException If a problem is encountered while parsing the
* provided string as a time range, or if the start
* time is greater than the end time.
*/
@Nullable()
static ObjectPair parseTimeRange(
@NotNull final String timeRangeStr,
final boolean strict)
throws LDAPException
{
final Date startTime;
final Date endTime;
try
{
// See if there is a comma to separate the before and after times. If so,
// then parse each value separately. Otherwise, the value will be just
// the start time and the current time will be used as the end time.
final int commaPos = timeRangeStr.indexOf(',');
if (commaPos > 0)
{
startTime = parseTimestamp(timeRangeStr.substring(0, commaPos).trim());
endTime = parseTimestamp(timeRangeStr.substring(commaPos+1).trim());
}
else
{
startTime = parseTimestamp(timeRangeStr);
endTime = null;
}
}
catch (final LDAPException e)
{
Debug.debugException(e);
// NOTE: The server-side version of the collect-support-data tool has a
// not-so-documented feature in which you can provide rotated file names
// as an alternative to an actual time range. We can't handle that
// when operating against a remote server, so we'll require strict
// timestamp compliance when --useRemoteServer is provided, but we'll just
// return null and let the argument value be passed through to the
// server-side code otherwise.
if (strict)
{
throw e;
}
else
{
return null;
}
}
if ((endTime != null) && (startTime.getTime() > endTime.getTime()))
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_CSD_TIME_RANGE_START_GREATER_THAN_END.get());
}
return new ObjectPair<>(startTime, endTime);
}
/**
* Parses the provided string as a timestamp value in either the generalized
* time format or the Ping Identity Directory Server's default access log
* format (with or without millisecond precision).
*
* @param timestampStr The timestamp to be parsed. It must not be
* {@code null}.
*
* @return The {@code Date} created by parsing the timestamp.
*
* @throws LDAPException If the provided string cannot be parsed as a
* valid timestamp.
*/
@NotNull()
static Date parseTimestamp(@NotNull final String timestampStr)
throws LDAPException
{
// First, try using the timestamp argument to parse the timestamp.
try
{
return TimestampArgument.parseTimestamp(timestampStr);
}
catch (final Exception e)
{
Debug.debugException(Level.FINEST, e);
}
// Next, try the server's default access log format with millisecond
// precision.
try
{
final SimpleDateFormat timestampFormatter =
new SimpleDateFormat(SERVER_LOG_TIMESTAMP_FORMAT_WITH_MILLIS);
timestampFormatter.setLenient(false);
return timestampFormatter.parse(timestampStr);
}
catch (final Exception e)
{
Debug.debugException(Level.FINEST, e);
}
// Next, try the server's default access log format with second precision.
try
{
final SimpleDateFormat timestampFormatter =
new SimpleDateFormat(SERVER_LOG_TIMESTAMP_FORMAT_WITHOUT_MILLIS);
timestampFormatter.setLenient(false);
return timestampFormatter.parse(timestampStr);
}
catch (final Exception e)
{
Debug.debugException(Level.FINEST, e);
}
// If we've gotten here, then we could not parse the timestamp.
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_CSD_TIME_RANGE_CANNOT_PARSE_TIMESTAMP.get(timestampStr));
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public ResultCode doToolProcessing()
{
// If the --useRemoteServer argument was provided, then use the extended
// operation to perform the processing. Otherwise, use reflection to invoke
// the server's version of the collect-support-data tool.
if (useRemoteServerArg.isPresent())
{
return doExtendedOperationProcessing();
}
else
{
return doLocalProcessing();
}
}
/**
* Performs the collect-support-data processing against a remote server using
* the extended operation.
*
* @return A result code that indicates the result of the processing.
*/
@NotNull()
private ResultCode doExtendedOperationProcessing()
{
// Create a connection pool that will be used to communicate with the
// server. Use an administrative session if appropriate.
final StartAdministrativeSessionPostConnectProcessor p;
if (useAdministrativeSessionArg.isPresent())
{
p = new StartAdministrativeSessionPostConnectProcessor(
new StartAdministrativeSessionExtendedRequest(getToolName(),
true));
}
else
{
p = null;
}
final LDAPConnectionPool pool;
try
{
pool = getConnectionPool(1, 1, 0, p, null, true,
new ReportBindResultLDAPConnectionPoolHealthCheck(this, true,
false));
}
catch (final LDAPException e)
{
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, e.getMessage());
toolCompletionMessage.set(e.getMessage());
return e.getResultCode();
}
try
{
// Create the properties to use for the extended request.
final CollectSupportDataExtendedRequestProperties properties =
new CollectSupportDataExtendedRequestProperties();
final File outputPath = outputPathArg.getValue();
if (outputPath != null)
{
if (! (outputPath.exists() && outputPath.isDirectory()))
{
properties.setArchiveFileName(outputPath.getName());
}
}
try
{
properties.setEncryptionPassphrase(
getEncryptionPassphraseForExtOpProcessing());
}
catch (final LDAPException e)
{
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, e.getMessage());
toolCompletionMessage.set(e.getMessage());
return e.getResultCode();
}
properties.setIncludeExpensiveData(collectExpensiveDataArg.isPresent());
properties.setIncludeReplicationStateDump(
collectReplicationStateDumpArg.isPresent());
properties.setIncludeBinaryFiles(includeBinaryFilesArg.isPresent());
properties.setIncludeExtensionSource(
archiveExtensionSourceArg.isPresent());
properties.setUseSequentialMode(sequentialArg.isPresent());
if (securityLevelArg.isPresent())
{
properties.setSecurityLevel(CollectSupportDataSecurityLevel.forName(
securityLevelArg.getValue()));
}
if (jstackCountArg.isPresent())
{
properties.setJStackCount(jstackCountArg.getValue());
}
if (reportCountArg.isPresent())
{
properties.setReportCount(reportCountArg.getValue());
}
if (reportIntervalSecondsArg.isPresent())
{
properties.setReportIntervalSeconds(
reportIntervalSecondsArg.getValue());
}
if (logTimeRangeArg.isPresent())
{
try
{
final ObjectPair timeRange =
parseTimeRange(logTimeRangeArg.getValue(), true);
properties.setLogCaptureWindow(
new TimeWindowCollectSupportDataLogCaptureWindow(
timeRange.getFirst(), timeRange.getSecond()));
}
catch (final LDAPException e)
{
// This should never happen because we should have pre-validated the
// value. But handle it just in case.
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, e.getMessage());
toolCompletionMessage.set(e.getMessage());
return e.getResultCode();
}
}
else if (logDurationArg.isPresent())
{
properties.setLogCaptureWindow(
new DurationCollectSupportDataLogCaptureWindow(
logDurationArg.getValue(TimeUnit.MILLISECONDS)));
}
else if (logFileHeadCollectionSizeKBArg.isPresent() ||
logFileTailCollectionSizeKBArg.isPresent())
{
properties.setLogCaptureWindow(
new HeadAndTailSizeCollectSupportDataLogCaptureWindow(
logFileHeadCollectionSizeKBArg.getValue(),
logFileTailCollectionSizeKBArg.getValue()));
}
if (commentArg.isPresent())
{
properties.setComment(commentArg.getValue());
}
if (proxyToServerAddressArg.isPresent())
{
properties.setProxyToServer(proxyToServerAddressArg.getValue(),
proxyToServerPortArg.getValue());
}
// Create the intermediate response listener that will be used to handle
// output and archive fragment messages.
ResultCode resultCode = null;
try (CollectSupportDataIRListener listener =
new CollectSupportDataIRListener(this, outputPathArg.getValue()))
{
// Construct the extended request to send to the server.
final Control[] controls;
if (dryRunArg.isPresent())
{
controls = new Control[]
{
new NoOpRequestControl()
};
}
else
{
controls = StaticUtils.NO_CONTROLS;
}
final CollectSupportDataExtendedRequest request =
new CollectSupportDataExtendedRequest(properties, listener,
controls);
request.setResponseTimeoutMillis(0L);
// Send the request and read the result.
final CollectSupportDataExtendedResult result;
try
{
result = (CollectSupportDataExtendedResult)
pool.processExtendedOperation(request);
}
catch (final LDAPException e)
{
Debug.debugException(e);
final String message = ERR_CSD_ERROR_SENDING_REQUEST.get(
StaticUtils.getExceptionMessage(e));
wrapErr(0, WRAP_COLUMN, message);
toolCompletionMessage.set(message);
return e.getResultCode();
}
resultCode = result.getResultCode();
final String diagnosticMessage = result.getDiagnosticMessage();
if (diagnosticMessage != null)
{
if ((resultCode == ResultCode.SUCCESS) ||
(resultCode == ResultCode.NO_OPERATION))
{
wrapOut(0, WRAP_COLUMN, diagnosticMessage);
}
else
{
wrapErr(0, WRAP_COLUMN, diagnosticMessage);
}
toolCompletionMessage.set(diagnosticMessage);
}
else
{
toolCompletionMessage.set(INFO_CSD_COMPLETED_WITH_RESULT_CODE.get(
String.valueOf(resultCode)));
}
}
catch (final IOException e)
{
Debug.debugException(e);
if (resultCode == ResultCode.SUCCESS)
{
resultCode = ResultCode.LOCAL_ERROR;
toolCompletionMessage.set(e.getMessage());
}
}
return resultCode;
}
finally
{
pool.close();
}
}
/**
* Retrieves the passphrase to use to generate the key for encrypting the
* support data archive. This method should only be used when the tool
* processing will be performed using an extended operation.
*
* @return The passphrase to use to generate the key for encrypting the
* support data archive.
*
* @throws LDAPException If a problem is encountered while attempting to
* obtain the passphrase.
*/
@Nullable()
private ASN1OctetString getEncryptionPassphraseForExtOpProcessing()
throws LDAPException
{
if (! encryptArg.isPresent())
{
return null;
}
if (passphraseFileArg.isPresent())
{
final File passphraseFile = passphraseFileArg.getValue();
if (generatePassphraseArg.isPresent())
{
// Generate a passphrase as a base64url-encoded representation of some
// randomly generated data.
final SecureRandom random = new SecureRandom();
final byte[] randomBytes = new byte[64];
random.nextBytes(randomBytes);
final String passphrase = Base64.urlEncode(randomBytes, false);
try (PrintWriter writer = new PrintWriter(passphraseFile))
{
writer.println(passphrase);
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_CSD_CANNOT_WRITE_GENERATED_PASSPHRASE.get(
passphraseFile.getAbsolutePath(),
StaticUtils.getExceptionMessage(e)),
e);
}
return new ASN1OctetString(passphrase);
}
else
{
try
{
final char[] passphrase =
getPasswordFileReader().readPassword(passphraseFile);
return new ASN1OctetString(new String(passphrase));
}
catch (final Exception e)
{
Debug.debugException(e);
ResultCode resultCode = ResultCode.LOCAL_ERROR;
if (e instanceof LDAPException)
{
resultCode = ((LDAPException) e).getResultCode();
}
throw new LDAPException(resultCode,
ERR_CSD_CANNOT_READ_PASSPHRASE.get(
passphraseFile.getAbsolutePath(),
StaticUtils.getExceptionMessage(e)),
e);
}
}
}
// Prompt for the encryption passphrase.
while (true)
{
try
{
getOut().print(INFO_CSD_PASSPHRASE_INITIAL_PROMPT.get());
final byte[] passphraseBytes = PasswordReader.readPassword();
getOut().print(INFO_CSD_PASSPHRASE_CONFIRM_PROMPT.get());
final byte[] confirmBytes = PasswordReader.readPassword();
if (Arrays.equals(passphraseBytes, confirmBytes))
{
return new ASN1OctetString(passphraseBytes);
}
else
{
wrapErr(0, WRAP_COLUMN, ERR_CSD_PASSPHRASE_MISMATCH.get());
err();
}
}
catch (final Exception e)
{
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_CSD_PASSPHRASE_PROMPT_READ_ERROR.get(
StaticUtils.getExceptionMessage(e)),
e);
}
}
}
/**
* Performs the collect-support-data tool using reflection to invoke the
* server-side version of the tool.
*
* @return A result code that indicates the result of the processing.
*/
@NotNull()
private ResultCode doLocalProcessing()
{
// Construct the argument list to use when invoking the server-side code.
// Although this tool supports all of the arguments that the server-side
// tool provides, the server-side tool does not support all of the arguments
// that this version offers, nor does it support all of the variants (e.g.,
// alternate names) for the arguments that do overlap.
final List argList = new ArrayList<>(20);
if (outputPathArg.isPresent())
{
argList.add("--outputPath");
argList.add(outputPathArg.getValue().getAbsolutePath());
}
if (noLDAPArg.isPresent())
{
argList.add("--noLdap");
}
if (pidArg.isPresent())
{
for (final Integer pid : pidArg.getValues())
{
argList.add("--pid");
argList.add(pid.toString());
}
}
if (sequentialArg.isPresent())
{
argList.add("--sequential");
}
if (reportCountArg.isPresent())
{
argList.add("--reportCount");
argList.add(reportCountArg.getValue().toString());
}
if (reportIntervalSecondsArg.isPresent())
{
argList.add("--reportInterval");
argList.add(reportIntervalSecondsArg.getValue().toString());
}
if (jstackCountArg.isPresent())
{
argList.add("--maxJstacks");
argList.add(jstackCountArg.getValue().toString());
}
if (collectExpensiveDataArg.isPresent())
{
argList.add("--collectExpensiveData");
}
if (collectReplicationStateDumpArg.isPresent())
{
argList.add("--collectReplicationStateDump");
}
if (commentArg.isPresent())
{
argList.add("--comment");
argList.add(commentArg.getValue());
}
if (includeBinaryFilesArg.isPresent())
{
argList.add("--includeBinaryFiles");
}
if (securityLevelArg.isPresent())
{
argList.add("--securityLevel");
argList.add(securityLevelArg.getValue());
}
if (encryptArg.isPresent())
{
argList.add("--encrypt");
}
if (passphraseFileArg.isPresent())
{
argList.add("--passphraseFile");
argList.add(passphraseFileArg.getValue().getAbsolutePath());
}
if (generatePassphraseArg.isPresent())
{
argList.add("--generatePassphrase");
}
if (decryptArg.isPresent())
{
argList.add("--decrypt");
argList.add(decryptArg.getValue().getAbsolutePath());
}
if (logTimeRangeArg.isPresent())
{
final ObjectPair timeRange;
try
{
timeRange = parseTimeRange(logTimeRangeArg.getValue(), false);
}
catch (final LDAPException e)
{
// This should never happen because we should have pre-validated the
// value. But handle it just in case.
Debug.debugException(e);
wrapErr(0, WRAP_COLUMN, e.getMessage());
return e.getResultCode();
}
if (timeRange == null)
{
// We'll assume that this means the time range was specified using
// rotated log filenames, which we can't handle in the LDAP SDK code so
// we'll just pass the argument value through to the server code.
argList.add("--timeRange");
argList.add(logTimeRangeArg.getValue());
}
else
{
final Date startTime = timeRange.getFirst();
Date endTime = timeRange.getSecond();
if (endTime == null)
{
endTime = new Date(Math.max(System.currentTimeMillis(),
startTime.getTime()));
}
final SimpleDateFormat timestampFormatter =
new SimpleDateFormat(SERVER_LOG_TIMESTAMP_FORMAT_WITH_MILLIS);
argList.add("--timeRange");
argList.add(timestampFormatter.format(startTime) + ',' +
timestampFormatter.format(endTime));
}
}
if (logDurationArg.isPresent())
{
argList.add("--duration");
argList.add(DurationArgument.nanosToDuration(
logDurationArg.getValue(TimeUnit.NANOSECONDS)));
}
if (logFileHeadCollectionSizeKBArg.isPresent())
{
argList.add("--logFileHeadCollectionSizeKB");
argList.add(String.valueOf(logFileHeadCollectionSizeKBArg.getValue()));
}
if (logFileTailCollectionSizeKBArg.isPresent())
{
argList.add("--logFileTailCollectionSizeKB");
argList.add(String.valueOf(logFileTailCollectionSizeKBArg.getValue()));
}
if (archiveExtensionSourceArg.isPresent())
{
argList.add("--archiveExtensionSource");
}
if (noPromptArg.isPresent())
{
argList.add("--no-prompt");
}
if (scriptFriendlyArg.isPresent())
{
argList.add("--script-friendly");
}
// We also need to include values for arguments provided by the LDAP
// command-line tool framework.
for (final String argumentIdentifier :
Arrays.asList("hostname", "port", "bindDN", "bindPassword",
"bindPasswordFile", "useSSL", "useStartTLS", "trustAll",
"keyStorePath", "keyStorePassword", "keyStorePasswordFile",
"trustStorePath", "trustStorePassword", "trustStorePasswordFile",
"certNickname", "saslOption", "propertiesFilePath",
"noPropertiesFile"))
{
final Argument arg = parser.getNamedArgument(argumentIdentifier);
if (arg.getNumOccurrences() > 0)
{
for (final String value : arg.getValueStringRepresentations(false))
{
argList.add("--" + argumentIdentifier);
if (arg.takesValue())
{
argList.add(value);
}
}
}
}
// If the --dryRun argument was provided, then return without actually
// invoking the tool.
if (dryRunArg.isPresent())
{
final String message = INFO_CSD_LOCAL_MODE_DRY_RUN.get();
wrapOut(0, WRAP_COLUMN, message);
toolCompletionMessage.set(message);
return ResultCode.NO_OPERATION;
}
// Make sure that we have access to the method in the server codebase that
// we need to invoke local collect-support-data processing.
final Method doMainMethod;
try
{
final Class> csdToolClass = Class.forName(SERVER_CSD_TOOL_CLASS);
doMainMethod = csdToolClass.getMethod("doMain", Boolean.TYPE,
OutputStream.class, OutputStream.class, String[].class);
}
catch (final Throwable t)
{
Debug.debugException(t);
final String message = ERR_CSD_SERVER_CODE_NOT_AVAILABLE.get();
wrapErr(0, WRAP_COLUMN, message);
toolCompletionMessage.set(message);
return ResultCode.NOT_SUPPORTED;
}
// Invoke the doMain method via reflection
final String[] argArray = new String[argList.size()];
argList.toArray(argArray);
try
{
final Object doMainMethodReturnValue = doMainMethod.invoke(null,
true, getOut(), getErr(), argArray);
final int exitCode = ((Integer) doMainMethodReturnValue).intValue();
return ResultCode.valueOf(exitCode);
}
catch (final Throwable t)
{
Debug.debugException(t);
final String message =
ERR_CSD_INVOKE_ERROR.get(StaticUtils.getExceptionMessage(t));
wrapErr(0, WRAP_COLUMN, message);
toolCompletionMessage.set(message);
return ResultCode.LOCAL_ERROR;
}
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public LinkedHashMap getExampleUsages()
{
final LinkedHashMap examples =
new LinkedHashMap<>(StaticUtils.computeMapCapacity(3));
examples.put(
new String[]
{
"--bindDN", "uid=admin,dc=example,dc=com",
"--bindPasswordFile", "admin-pw.txt"
},
INFO_CSD_EXAMPLE_1.get());
examples.put(
new String[]
{
"--useRemoteServer",
"--hostname", "ds.example.com",
"--port", "636",
"--useSSL",
"--trustStorePath", "config/truststore",
"--bindDN", "uid=admin,dc=example,dc=com",
"--bindPasswordFile", "admin-pw.txt",
"--collectExpensiveData",
"--collectReplicationStateDump",
"--securityLevel", "maximum",
"--logDuration", "10 minutes",
"--encrypt",
"--passphraseFile", "encryption-passphrase.txt",
"--generatePassphrase",
"--outputPath", "csd.zip"
},
INFO_CSD_EXAMPLE_2.get());
examples.put(
new String[]
{
"--decrypt", "support-data-ds-inst1-" +
StaticUtils.encodeGeneralizedTime(new Date()) +
"-zip-encrypted",
"--passphraseFile", "encryption-passphrase.txt"
},
INFO_CSD_EXAMPLE_3.get());
return examples;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy