Skip to content

Commit 343bf5f

Browse files
shintaroonumasteveloughran
authored andcommitted
HADOOP-18938. S3A: Fix endpoint region parsing for vpc endpoints. (#6466)
Contributed by Shintaro Onuma
1 parent edfd10e commit 343bf5f

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/DefaultS3ClientFactory.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.io.IOException;
2222
import java.net.URI;
2323
import java.net.URISyntaxException;
24+
import java.util.regex.Matcher;
25+
import java.util.regex.Pattern;
2426

2527
import org.apache.hadoop.classification.VisibleForTesting;
2628
import org.apache.hadoop.fs.s3a.impl.AWSClientConfig;
@@ -82,6 +84,9 @@ public class DefaultS3ClientFactory extends Configured
8284

8385
private static final String S3_SERVICE_NAME = "s3";
8486

87+
private static final Pattern VPC_ENDPOINT_PATTERN =
88+
Pattern.compile("^(?:.+\\.)?([a-z0-9-]+)\\.vpce\\.amazonaws\\.(?:com|com\\.cn)$");
89+
8590
/**
8691
* Subclasses refer to this.
8792
*/
@@ -380,10 +385,19 @@ private static URI getS3Endpoint(String endpoint, final Configuration conf) {
380385
* @param endpointEndsWithCentral true if the endpoint is configured as central.
381386
* @return the S3 region, null if unable to resolve from endpoint.
382387
*/
383-
private static Region getS3RegionFromEndpoint(final String endpoint,
388+
@VisibleForTesting
389+
static Region getS3RegionFromEndpoint(final String endpoint,
384390
final boolean endpointEndsWithCentral) {
385391

386392
if (!endpointEndsWithCentral) {
393+
// S3 VPC endpoint parsing
394+
Matcher matcher = VPC_ENDPOINT_PATTERN.matcher(endpoint);
395+
if (matcher.find()) {
396+
LOG.debug("Mapping to VPCE");
397+
LOG.debug("Endpoint {} is vpc endpoint; parsing region as {}", endpoint, matcher.group(1));
398+
return Region.of(matcher.group(1));
399+
}
400+
387401
LOG.debug("Endpoint {} is not the default; parsing", endpoint);
388402
return AwsHostNameUtils.parseSigningRegion(endpoint, S3_SERVICE_NAME).orElse(null);
389403
}

hadoop-tools/hadoop-aws/src/test/java/org/apache/hadoop/fs/s3a/ITestS3AEndpointRegion.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ public class ITestS3AEndpointRegion extends AbstractS3ATestBase {
9797

9898
private static final String VPC_ENDPOINT = "vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com";
9999

100+
private static final String CN_VPC_ENDPOINT = "vpce-1a2b3c4d-5e6f.s3.cn-northwest-1.vpce.amazonaws.com.cn";
101+
100102
public static final String EXCEPTION_THROWN_BY_INTERCEPTOR = "Exception thrown by interceptor";
101103

102104
/**
@@ -294,7 +296,6 @@ public void testWithGovCloudEndpoint() throws Throwable {
294296
}
295297

296298
@Test
297-
@Ignore("Pending HADOOP-18938. S3A region logic to handle vpce and non standard endpoints")
298299
public void testWithVPCE() throws Throwable {
299300
describe("Test with vpc endpoint");
300301
Configuration conf = getConfiguration();
@@ -304,6 +305,16 @@ public void testWithVPCE() throws Throwable {
304305
expectInterceptorException(client);
305306
}
306307

308+
@Test
309+
public void testWithChinaVPCE() throws Throwable {
310+
describe("Test with china vpc endpoint");
311+
Configuration conf = getConfiguration();
312+
313+
S3Client client = createS3Client(conf, CN_VPC_ENDPOINT, null, CN_NORTHWEST_1, false);
314+
315+
expectInterceptorException(client);
316+
}
317+
307318
@Test
308319
public void testCentralEndpointAndDifferentRegionThanBucket() throws Throwable {
309320
describe("Access public bucket using central endpoint and region "
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.fs.s3a;
20+
21+
import org.assertj.core.api.Assertions;
22+
import org.junit.Test;
23+
import software.amazon.awssdk.regions.Region;
24+
25+
public class TestS3AEndpointParsing extends AbstractS3AMockTest {
26+
27+
private static final String VPC_ENDPOINT = "vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com";
28+
private static final String NON_VPC_ENDPOINT = "s3.eu-west-1.amazonaws.com";
29+
private static final String US_WEST_2 = "us-west-2";
30+
private static final String EU_WEST_1 = "eu-west-1";
31+
32+
@Test
33+
public void testVPCEndpoint() {
34+
Region region = DefaultS3ClientFactory.getS3RegionFromEndpoint(VPC_ENDPOINT, false);
35+
Assertions.assertThat(region).isEqualTo(Region.of(US_WEST_2));
36+
}
37+
38+
@Test
39+
public void testNonVPCEndpoint() {
40+
Region region = DefaultS3ClientFactory.getS3RegionFromEndpoint(NON_VPC_ENDPOINT, false);
41+
Assertions.assertThat(region).isEqualTo(Region.of(EU_WEST_1));
42+
}
43+
}

0 commit comments

Comments
 (0)