HADOOP-18085. S3 SDK Upgrade causes AccessPoint ARN endpoint mistranslation (#3902)

Part of HADOOP-17198. Support S3 Access Points.

HADOOP-18068. "upgrade AWS SDK to 1.12.132" broke the access point endpoint
translation.

Correct endpoints should start with "s3-accesspoint.", after SDK upgrade they start with
"s3.accesspoint-" which messes up tests + region detection by the SDK.

Contributed by Bogdan Stolojan

Change-Id: I0c0181628ab803afc39036003777eaec79aa378c
This commit is contained in:
Petre Bogdan Stolojan 2022-02-04 15:37:08 +00:00 committed by Steve Loughran
parent cf2675f721
commit 744f0bd4f7
No known key found for this signature in database
GPG Key ID: D22CF846DBB162A0
2 changed files with 39 additions and 19 deletions

View File

@ -21,12 +21,12 @@ package org.apache.hadoop.fs.s3a;
import javax.annotation.Nonnull;
import com.amazonaws.arn.Arn;
import com.amazonaws.regions.RegionUtils;
/**
* Represents an Arn Resource, this can be an accesspoint or bucket.
*/
public final class ArnResource {
private final static String ACCESSPOINT_ENDPOINT_FORMAT = "s3-accesspoint.%s.amazonaws.com";
/**
* Resource name.
@ -106,8 +106,7 @@ public final class ArnResource {
* @return resource endpoint.
*/
public String getEndpoint() {
return RegionUtils.getRegion(accessPointRegionKey)
.getServiceEndpoint("s3");
return String.format(ACCESSPOINT_ENDPOINT_FORMAT, region);
}
/**

View File

@ -39,39 +39,43 @@ import static org.apache.hadoop.test.LambdaTestUtils.intercept;
public class TestArnResource extends HadoopTestBase {
private final static Logger LOG = LoggerFactory.getLogger(TestArnResource.class);
private final static String MOCK_ACCOUNT = "123456789101";
@Test
public void parseAccessPointFromArn() throws IllegalArgumentException {
describe("Parse AccessPoint ArnResource from arn string");
String accessPoint = "testAp";
String accountId = "123456789101";
String[][] regionPartitionEndpoints = new String[][] {
{Regions.EU_WEST_1.getName(), "aws", "eu-west-1.amazonaws.com"},
{Regions.US_GOV_EAST_1.getName(), "aws-us-gov",
"us-gov-east-1.amazonaws.com"},
{Regions.CN_NORTH_1.getName(), "aws-cn", "cn-north-1.amazonaws.com"},
{Regions.EU_WEST_1.getName(), "aws"},
{Regions.US_GOV_EAST_1.getName(), "aws-us-gov"},
{Regions.CN_NORTH_1.getName(), "aws-cn"},
};
for (String[] testPair : regionPartitionEndpoints) {
String region = testPair[0];
String partition = testPair[1];
String endpoint = testPair[2];
// arn:partition:service:region:account-id:resource-type/resource-id
String arn = String.format("arn:%s:s3:%s:%s:accesspoint/%s", partition, region, accountId,
accessPoint);
ArnResource resource = ArnResource.accessPointFromArn(arn);
assertEquals("Arn does not match", arn, resource.getFullArn());
ArnResource resource = getArnResourceFrom(partition, region, MOCK_ACCOUNT, accessPoint);
assertEquals("Access Point name does not match", accessPoint, resource.getName());
assertEquals("Account Id does not match", accountId, resource.getOwnerAccountId());
assertEquals("Account Id does not match", MOCK_ACCOUNT, resource.getOwnerAccountId());
assertEquals("Region does not match", region, resource.getRegion());
Assertions.assertThat(resource.getEndpoint())
.describedAs("Endpoint does not match")
.contains(endpoint);
}
}
@Test
public void makeSureEndpointHasTheCorrectFormat() {
// Access point (AP) endpoints are different from S3 bucket endpoints, thus when using APs the
// endpoints for the client are modified. This test makes sure endpoint is set up correctly.
ArnResource accessPoint = getArnResourceFrom("aws", "eu-west-1", MOCK_ACCOUNT,
"test");
String expected = "s3-accesspoint.eu-west-1.amazonaws.com";
Assertions.assertThat(accessPoint.getEndpoint())
.describedAs("Endpoint has invalid format. Access Point requests will not work")
.isEqualTo(expected);
}
@Test
public void invalidARNsMustThrow() throws Exception {
describe("Using an invalid ARN format must throw when initializing an ArnResource.");
@ -80,6 +84,23 @@ public class TestArnResource extends HadoopTestBase {
ArnResource.accessPointFromArn("invalid:arn:resource"));
}
/**
* Create an {@link ArnResource} from string components
* @param partition - partition for ARN
* @param region - region for ARN
* @param accountId - accountId for ARN
* @param resourceName - ARN resource name
* @return ArnResource described by its properties
*/
private ArnResource getArnResourceFrom(String partition, String region, String accountId,
String resourceName) {
// arn:partition:service:region:account-id:resource-type/resource-id
String arn = String.format("arn:%s:s3:%s:%s:accesspoint/%s", partition, region, accountId,
resourceName);
return ArnResource.accessPointFromArn(arn);
}
private void describe(String message) {
LOG.info(message);
}