Skip to content

Commit 52fbfae

Browse files
authored
fix: Backblaze Integration by hardcoding list of clusters (#1479)
Removed the call to b2_authorized_account and added in a hardcoded list of clusters. Meta's servers require IPv6 APIs which the B2 Native API doesn't support yet.
1 parent ca092c7 commit 52fbfae

5 files changed

Lines changed: 65 additions & 190 deletions

File tree

extensions/data-transfer/portability-data-transfer-backblaze/src/main/java/org/datatransferproject/datatransfer/backblaze/common/BackblazeDataTransferClient.java

Lines changed: 30 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,10 @@
2121
import java.io.IOException;
2222
import java.io.InputStream;
2323
import java.util.ArrayList;
24-
import java.util.Base64;
2524
import java.util.List;
2625
import org.apache.commons.lang3.RandomStringUtils;
27-
import org.apache.http.client.methods.CloseableHttpResponse;
28-
import org.apache.http.client.methods.HttpGet;
29-
import org.apache.http.impl.client.CloseableHttpClient;
30-
import org.apache.http.impl.client.HttpClientBuilder;
31-
import org.apache.http.util.EntityUtils;
3226
import org.datatransferproject.api.launcher.Monitor;
3327
import org.datatransferproject.datatransfer.backblaze.exception.BackblazeCredentialsException;
34-
import org.json.simple.JSONObject;
35-
import org.json.simple.parser.JSONParser;
36-
import org.json.simple.parser.ParseException;
3728
import software.amazon.awssdk.awscore.exception.AwsServiceException;
3829
import software.amazon.awssdk.core.exception.SdkClientException;
3930
import software.amazon.awssdk.core.sync.RequestBody;
@@ -75,6 +66,18 @@
7566
public class BackblazeDataTransferClient {
7667
private static final String DATA_TRANSFER_BUCKET_PREFIX_FORMAT_STRING = "%s-data-transfer";
7768
private static final int MAX_BUCKET_CREATION_ATTEMPTS = 10;
69+
// Backblaze B2 Native API only supports IPv4; until it supports IPv6 we cannot use
70+
// the b2_authorize_account endpoint to look up what region an account is in. For now
71+
// a hard-coded list will be maintained and updated if the cluster list changes.
72+
private static final List<String> REGIONS = List.of(
73+
"us-west-000",
74+
"us-west-001",
75+
"us-west-002",
76+
"us-west-004",
77+
"us-east-005",
78+
"eu-central-003",
79+
"ca-east-006"
80+
);
7881

7982
private final long sizeThresholdForMultipartUpload;
8083
private final long partSizeForMultiPartUpload;
@@ -97,21 +100,28 @@ public BackblazeDataTransferClient(
97100
this.partSizeForMultiPartUpload = partSizeForMultiPartUpload;
98101
}
99102

100-
public void init(
101-
String keyId, String applicationKey, String exportService, CloseableHttpClient httpClient)
103+
public void init(String keyId, String applicationKey, String exportService)
102104
throws BackblazeCredentialsException, IOException {
103105
// Fetch all the available buckets and use that to find which region the user is in
104106
ListBucketsResponse listBucketsResponse = null;
107+
String successfulRegion = null;
105108

106109
Throwable s3Exception = null;
107-
String userRegion = getAccountRegion(httpClient, keyId, applicationKey);
108-
s3Client = backblazeS3ClientFactory.createS3Client(keyId, applicationKey, userRegion);
109-
try {
110-
listBucketsResponse = s3Client.listBuckets();
111-
} catch (S3Exception e) {
112-
s3Exception = e;
113-
if (s3Client != null) {
114-
s3Client.close();
110+
for (String region : REGIONS) {
111+
S3Client potentialS3Client =
112+
backblazeS3ClientFactory.createS3Client(keyId, applicationKey, region);
113+
try {
114+
listBucketsResponse = potentialS3Client.listBuckets();
115+
s3Client = potentialS3Client;
116+
successfulRegion = region;
117+
monitor.info(() -> "Successfully connected to Backblaze region: " + region);
118+
break;
119+
} catch (S3Exception e) {
120+
monitor.info(() -> "Failed to connect to Backblaze region: " + region);
121+
s3Exception = e;
122+
if (potentialS3Client != null) {
123+
potentialS3Client.close();
124+
}
115125
}
116126
}
117127

@@ -120,7 +130,7 @@ public void init(
120130
"User's credentials or permissions are not valid for any regions available", s3Exception);
121131
}
122132

123-
bucketName = getOrCreateBucket(s3Client, listBucketsResponse, userRegion, exportService);
133+
bucketName = getOrCreateBucket(s3Client, listBucketsResponse, successfulRegion, exportService);
124134
}
125135

126136
public String uploadFile(String fileKey, File file) throws IOException {
@@ -154,42 +164,6 @@ public String uploadFile(String fileKey, File file) throws IOException {
154164
}
155165
}
156166

157-
private String getAccountRegion(
158-
CloseableHttpClient httpClient, String keyId, String applicationKey)
159-
throws BackblazeCredentialsException {
160-
161-
String auth = keyId + ":" + applicationKey;
162-
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
163-
String authHeaderValue = "Basic " + new String(encodedAuth);
164-
165-
HttpGet request = new HttpGet("https://api.backblazeb2.com/b2api/v2/b2_authorize_account");
166-
request.addHeader("Authorization", authHeaderValue);
167-
168-
try {
169-
CloseableHttpResponse response = httpClient.execute(request);
170-
try (response) {
171-
int statusCode = response.getStatusLine().getStatusCode();
172-
173-
if (statusCode == 200) {
174-
String responseBody = EntityUtils.toString(response.getEntity());
175-
JSONParser parser = new JSONParser();
176-
JSONObject jsonResponse = (JSONObject) parser.parse(responseBody);
177-
String s3ApiUrl = (String) jsonResponse.get("s3ApiUrl");
178-
String region = s3ApiUrl.split("s3.")[1].split("\\.")[0];
179-
monitor.info(() -> "Region extracted from s3ApiUrl: " + region);
180-
return region;
181-
} else if (statusCode >= 400 && statusCode < 500) {
182-
// Don't retry on client errors (4xx)
183-
throw new BackblazeCredentialsException(
184-
"Failed to retrieve account's region. Status code: " + statusCode, null);
185-
} else {
186-
throw new IOException("Server returned status code: " + statusCode);
187-
}
188-
}
189-
} catch (IOException | ParseException e) {
190-
throw new BackblazeCredentialsException("Failed to retrieve account's region", e);
191-
}
192-
}
193167

194168
private String uploadFileUsingMultipartUpload(String fileKey, File file, long contentLength)
195169
throws IOException, AwsServiceException, SdkClientException {

extensions/data-transfer/portability-data-transfer-backblaze/src/main/java/org/datatransferproject/datatransfer/backblaze/common/BackblazeDataTransferClientFactory.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222
import java.util.UUID;
23-
import org.apache.http.impl.client.HttpClientBuilder;
2423
import org.datatransferproject.api.launcher.Monitor;
2524
import org.datatransferproject.datatransfer.backblaze.exception.BackblazeCredentialsException;
2625
import org.datatransferproject.transfer.JobMetadata;
@@ -49,12 +48,10 @@ public BackblazeDataTransferClient getOrCreateB2Client( UUID jobId,
4948
SIZE_THRESHOLD_FOR_MULTIPART_UPLOAD,
5049
PART_SIZE_FOR_MULTIPART_UPLOAD);
5150
String exportService = JobMetadata.getExportService();
52-
CustomIPv4DnsResolver customDnsResolver = new CustomIPv4DnsResolver();
5351
backblazeDataTransferClient.init(
5452
authData.getToken(),
5553
authData.getSecret(),
56-
exportService,
57-
HttpClientBuilder.create().setDnsResolver(customDnsResolver).build()
54+
exportService
5855
);
5956
backblazeDataTransferClientMap.put(jobId, backblazeDataTransferClient);
6057
}

extensions/data-transfer/portability-data-transfer-backblaze/src/main/java/org/datatransferproject/datatransfer/backblaze/common/BackblazeIntegrationTest.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
package org.datatransferproject.datatransfer.backblaze.common;
2-
3-
import org.apache.http.impl.client.HttpClientBuilder;
42
import org.datatransferproject.api.launcher.Monitor;
53
import org.datatransferproject.launcher.monitor.ConsoleMonitor;
64

@@ -34,7 +32,7 @@ public static void main(String[] args) throws Exception {
3432

3533
// Initialize client with your credentials
3634
// The "test-service" string is used as a prefix for bucket naming
37-
client.init(keyId, appKey, "test-service", HttpClientBuilder.create().build());
35+
client.init(keyId, appKey, "test-service");
3836

3937
System.out.println("Client initialized successfully!");
4038

extensions/data-transfer/portability-data-transfer-backblaze/src/main/java/org/datatransferproject/datatransfer/backblaze/common/CustomIPv4DnsResolver.java

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)