HADOOP-16953. tuning s3guard disabled warnings (#1962)

Contributed by Steve Loughran.

The S3Guard absence warning of HADOOP-16484 has been changed
so that by default the S3A connector only logs at debug
when the connection to the S3 Store does not have S3Guard
enabled.

The option to control this log level is now
fs.s3a.s3guard.disabled.warn.level
and can be one of: silent, inform, warn, fail.

On a failure, an ExitException is raised with exit code 49.

For details on this safety feature, consult the s3guard documentation.

Change-Id: If868671c9260977c2b03b3e475b9c9531c98ce79
This commit is contained in:
Steve Loughran 2020-04-20 15:05:55 +01:00
parent de9a6b4588
commit 0982f56f3a
No known key found for this signature in database
GPG Key ID: D22CF846DBB162A0
4 changed files with 72 additions and 13 deletions

View File

@ -746,9 +746,9 @@ public final class Constants {
* The warn level if S3Guard is disabled.
*/
public static final String S3GUARD_DISABLED_WARN_LEVEL
= "org.apache.hadoop.fs.s3a.s3guard.disabled.warn.level";
= "fs.s3a.s3guard.disabled.warn.level";
public static final String DEFAULT_S3GUARD_DISABLED_WARN_LEVEL =
"INFORM";
"SILENT";
/**
* Inconsistency (visibility delay) injection settings.

View File

@ -53,12 +53,14 @@ import org.apache.hadoop.fs.s3a.Retries;
import org.apache.hadoop.fs.s3a.Retries.RetryTranslated;
import org.apache.hadoop.fs.s3a.S3AFileStatus;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.util.ExitUtil;
import org.apache.hadoop.util.ReflectionUtils;
import static org.apache.hadoop.fs.s3a.Constants.*;
import static org.apache.hadoop.fs.s3a.Constants.DEFAULT_AUTHORITATIVE_PATH;
import static org.apache.hadoop.fs.s3a.S3AUtils.createUploadFileStatus;
import static org.apache.hadoop.fs.s3a.s3guard.PathMetadataDynamoDBTranslation.authoritativeEmptyDirectoryMarker;
import static org.apache.hadoop.service.launcher.LauncherExitCodes.EXIT_BAD_CONFIGURATION;
/**
* Logic for integrating MetadataStore with S3A.
@ -1041,12 +1043,22 @@ public final class S3Guard {
return false;
}
/**
* Format string to use when warning that S3Guard is disabled.
*/
@VisibleForTesting
public static final String DISABLED_LOG_MSG =
"S3Guard is disabled on this bucket: {}";
"S3Guard is disabled on this bucket: %s";
/**
* Error string use in exception raised on an unknown log level.
*/
public static final String UNKNOWN_WARN_LEVEL =
"Unknown S3Guard disabled warn level: ";
"Unknown " + S3GUARD_DISABLED_WARN_LEVEL + " value: ";
/**
* Warning levels to use when reporting S3Guard as disabled.
*/
public enum DisabledWarnLevel {
SILENT,
INFORM,
@ -1054,9 +1066,18 @@ public final class S3Guard {
FAIL
}
/**
* Log that S3Guard is disabled -optionally raise an exception.
* @param logger Log to log to
* @param warnLevelStr string value of warn action.
* @param bucket bucket to use in log/error messages
* @throws ExitUtil.ExitException if s3guard was disabled
* and the log level is "fail"
* @throws IllegalArgumentException unknown warning level.
*/
public static void logS3GuardDisabled(Logger logger, String warnLevelStr,
String bucket)
throws UnsupportedOperationException, IllegalArgumentException {
throws ExitUtil.ExitException, IllegalArgumentException {
final DisabledWarnLevel warnLevel;
try {
warnLevel = DisabledWarnLevel.valueOf(warnLevelStr.toUpperCase(Locale.US));
@ -1064,19 +1085,20 @@ public final class S3Guard {
throw new IllegalArgumentException(UNKNOWN_WARN_LEVEL + warnLevelStr, e);
}
String text = String.format(DISABLED_LOG_MSG, bucket);
switch (warnLevel) {
case SILENT:
logger.debug(DISABLED_LOG_MSG, bucket);
logger.debug(text);
break;
case INFORM:
logger.info(DISABLED_LOG_MSG, bucket);
logger.info(text);
break;
case WARN:
logger.warn(DISABLED_LOG_MSG, bucket);
logger.warn(text);
break;
case FAIL:
logger.error(DISABLED_LOG_MSG, bucket);
throw new UnsupportedOperationException(DISABLED_LOG_MSG + bucket);
logger.error(text);
throw new ExitUtil.ExitException(EXIT_BAD_CONFIGURATION, text);
default:
throw new IllegalArgumentException(UNKNOWN_WARN_LEVEL + warnLevelStr);
}

View File

@ -1236,6 +1236,35 @@ Deleting the metadata store table will simply result in a period of eventual
consistency for any file modifications that were made right before the table
was deleted.
### Enabling a log message whenever S3Guard is *disabled*
When dealing with support calls related to the S3A connector, "is S3Guard on?"
is the usual opening question. This can be determined by looking at the application logs for
messages about S3Guard starting -the absence of S3Guard can only be inferred by the absence
of such messages.
There is a another strategy: have the S3A Connector log whenever *S3Guard is not enabled*
This can be done in the configuration option `fs.s3a.s3guard.disabled.warn.level`
```xml
<property>
<name>fs.s3a.s3guard.disabled.warn.level</name>
<value>silent</value>
<description>
Level to print a message when S3Guard is disabled.
Values:
"warn": log at WARN level
"inform": log at INFO level
"silent": log at DEBUG level
"fail": raise an exception
</description>
</property>
```
The `fail` option is clearly more than logging; it exists as an extreme debugging
tool. Use with care.
### Failure Semantics
Operations which modify metadata will make changes to S3 first. If, and only

View File

@ -41,7 +41,9 @@ import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.s3a.S3AFileStatus;
import org.apache.hadoop.fs.s3a.Tristate;
import org.apache.hadoop.service.launcher.LauncherExitCodes;
import org.apache.hadoop.test.LambdaTestUtils;
import org.apache.hadoop.util.ExitUtil;
import static org.apache.hadoop.fs.s3a.Constants.DEFAULT_METADATASTORE_METADATA_TTL;
import static org.apache.hadoop.fs.s3a.Constants.METADATASTORE_METADATA_TTL;
@ -429,11 +431,17 @@ public class TestS3Guard extends Assert {
S3Guard.DisabledWarnLevel.WARN.toString()
.toLowerCase(Locale.US), "bucket");
LambdaTestUtils.intercept(UnsupportedOperationException.class,
S3Guard.DISABLED_LOG_MSG, () -> S3Guard.logS3GuardDisabled(
ExitUtil.ExitException ex = LambdaTestUtils.intercept(
ExitUtil.ExitException.class,
String.format(S3Guard.DISABLED_LOG_MSG, "bucket"),
() -> S3Guard.logS3GuardDisabled(
localLogger, S3Guard.DisabledWarnLevel.FAIL.toString(), "bucket"));
if (ex.getExitCode() != LauncherExitCodes.EXIT_BAD_CONFIGURATION) {
throw ex;
}
LambdaTestUtils.intercept(IllegalArgumentException.class,
S3Guard.UNKNOWN_WARN_LEVEL, () -> S3Guard.logS3GuardDisabled(
S3Guard.UNKNOWN_WARN_LEVEL,
() -> S3Guard.logS3GuardDisabled(
localLogger, "FOO_BAR_LEVEL", "bucket"));
}