Skip to content

Commit 941af45

Browse files
committed
Catch known exceptions in ProgramFailureException
1 parent a9967d5 commit 941af45

File tree

1 file changed

+95
-30
lines changed

1 file changed

+95
-30
lines changed

src/main/java/io/cdap/plugin/gcp/gcs/StorageClient.java

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@
2828
import com.google.cloud.storage.StorageException;
2929
import com.google.cloud.storage.StorageOptions;
3030
import com.google.common.annotations.VisibleForTesting;
31+
import io.cdap.cdap.api.exception.ErrorCategory;
32+
import io.cdap.cdap.api.exception.ErrorType;
33+
import io.cdap.cdap.api.exception.ErrorUtils;
3134
import io.cdap.plugin.gcp.common.GCPConnectorConfig;
35+
import io.cdap.plugin.gcp.common.GCPErrorDetailsProviderUtil;
3236
import io.cdap.plugin.gcp.common.GCPUtils;
3337
import org.slf4j.Logger;
3438
import org.slf4j.LoggerFactory;
@@ -68,7 +72,14 @@ public Blob pickABlob(String path) {
6872
return null;
6973
}
7074
GCSPath gcsPath = GCSPath.from(path);
71-
Page<Blob> blobPage = storage.list(gcsPath.getBucket(), Storage.BlobListOption.prefix(gcsPath.getName()));
75+
Page<Blob> blobPage;
76+
try {
77+
blobPage = storage.list(gcsPath.getBucket(), Storage.BlobListOption.prefix(gcsPath.getName()));
78+
} catch (Exception e) {
79+
String errorReason = String.format("Unable to list objects in bucket %s.", gcsPath.getBucket());
80+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
81+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
82+
}
7283
Iterator<Blob> iterator = blobPage.getValues().iterator();
7384
while (iterator.hasNext()) {
7485
Blob blob = iterator.next();
@@ -89,7 +100,13 @@ public void setMetaData(Blob blob, Map<String, String> metaData) {
89100
if (blob == null || metaData == null || metaData.isEmpty()) {
90101
return;
91102
}
92-
storage.update(BlobInfo.newBuilder(blob.getBlobId()).setMetadata(metaData).build());
103+
try {
104+
storage.update(BlobInfo.newBuilder(blob.getBlobId()).setMetadata(metaData).build());
105+
} catch (Exception e) {
106+
String errorReason = String.format("Unable to update metadata for blob %s.", blob.getName());
107+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
108+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
109+
}
93110
}
94111

95112
/**
@@ -132,9 +149,11 @@ public void createBucketIfNotExists(GCSPath path, @Nullable String location, @Nu
132149
LOG.warn("Getting 409 Conflict: {} Bucket at destination path {} may already exist.",
133150
e.getMessage(), path.getUri());
134151
} else {
135-
throw new RuntimeException(
152+
String errorReason =
136153
String.format("Unable to create bucket %s. Ensure you entered the correct bucket path and " +
137-
"have permissions for it.", path.getBucket()), e);
154+
"have permissions for it.", path.getBucket());
155+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
156+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
138157
}
139158
}
140159
}
@@ -173,9 +192,16 @@ public void move(GCSPath sourcePath, GCSPath destPath, boolean recursive, boolea
173192
* Get all the matching wildcard paths given the regex input.
174193
*/
175194
public List<GCSPath> getMatchedPaths(GCSPath sourcePath, boolean recursive, Pattern wildcardRegex) {
176-
Page<Blob> blobPage = storage.list(sourcePath.getBucket(), Storage.BlobListOption.prefix(
195+
Page<Blob> blobPage;
196+
try {
197+
blobPage = storage.list(sourcePath.getBucket(), Storage.BlobListOption.prefix(
177198
getWildcardPathPrefix(sourcePath, wildcardRegex)
178-
));
199+
));
200+
} catch (Exception e) {
201+
String errorReason = String.format("Unable to list objects in bucket %s.", sourcePath.getBucket());
202+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
203+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
204+
}
179205
List<String> blobPageNames = new ArrayList<>();
180206
blobPage.getValues().forEach(blob -> blobPageNames.add(blob.getName()));
181207
return getFilterMatchedPaths(sourcePath, blobPageNames, recursive);
@@ -212,58 +238,84 @@ static List<GCSPath> getFilterMatchedPaths(GCSPath sourcePath, List<String> blob
212238
private void pairTraverse(GCSPath sourcePath, GCSPath destPath, boolean recursive, boolean overwrite,
213239
Consumer<BlobPair> consumer) {
214240

215-
Bucket sourceBucket = null;
241+
Bucket sourceBucket;
216242
try {
217243
sourceBucket = storage.get(sourcePath.getBucket());
218-
} catch (StorageException e) {
244+
} catch (Exception e) {
219245
// Add more descriptive error message
220-
throw new RuntimeException(
221-
String.format("Unable to access source bucket %s. ", sourcePath.getBucket())
222-
+ "Ensure you entered the correct bucket path.", e);
246+
String errorReason = String.format("Unable to access GCS bucket '%s'", sourcePath.getBucket());
247+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
248+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
223249
}
224250
if (sourceBucket == null) {
225-
throw new IllegalArgumentException(
226-
String.format("Source bucket '%s' does not exist.", sourcePath.getBucket()));
251+
String errorReason = String.format("Source bucket '%s' does not exist.", sourcePath.getBucket());
252+
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
253+
errorReason, errorReason, ErrorType.USER, true, null);
227254
}
228-
Bucket destBucket = null;
255+
Bucket destBucket;
229256
try {
230257
destBucket = storage.get(destPath.getBucket());
231-
} catch (StorageException e) {
258+
} catch (Exception e) {
232259
// Add more descriptive error message
233-
throw new RuntimeException(
234-
String.format("Unable to access destination bucket %s. ", destPath.getBucket())
235-
+ "Ensure you entered the correct bucket path.", e);
260+
String errorReason = String.format("Unable to access GCS bucket '%s'", destPath.getBucket());
261+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
262+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
236263
}
237264
if (destBucket == null) {
238-
throw new IllegalArgumentException(
239-
String.format("Destination bucket '%s' does not exist. Please create it first.", destPath.getBucket()));
265+
String errorReason =
266+
String.format("Destination bucket '%s' does not exist. Please create it first.", destPath.getBucket());
267+
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
268+
errorReason, errorReason, ErrorType.USER, true, null);
240269
}
241270

242271
boolean destinationBaseExists;
243272
String baseDestName = destPath.getName();
244-
if (destPath.isBucket() || storage.get(BlobId.of(destPath.getBucket(), baseDestName)) != null) {
273+
boolean destinationBlobExists;
274+
try {
275+
destinationBlobExists = destPath.isBucket() || storage.get(BlobId.of(destPath.getBucket(), baseDestName)) != null;
276+
} catch (Exception e) {
277+
String errorReason = String.format("Unable to access GCS bucket '%s'", destPath.getBucket());
278+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
279+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
280+
}
281+
if (destinationBlobExists) {
245282
destinationBaseExists = true;
246283
} else {
247284
// if gs://bucket2/subdir doesn't exist, check if gs://bucket2/subdir/ exists
248285
// similarly, if gs://bucket2/subdir/ doesn't exist, check if gs://bucket2/subdir exists
249286
// this is because "cp dir0 subdir" and "cp dir0 subdir/" are equivalent if the 'subdir' directory exists
250287
String modifiedName = baseDestName.endsWith("/") ?
251288
baseDestName.substring(0, baseDestName.length() - 1) : baseDestName + "/";
252-
destinationBaseExists = storage.get(BlobId.of(destPath.getBucket(), modifiedName)) != null;
289+
try {
290+
destinationBaseExists = storage.get(BlobId.of(destPath.getBucket(), modifiedName)) != null;
291+
} catch (Exception e) {
292+
String errorReason = String.format("Unable to access GCS bucket '%s'", destPath.getBucket());
293+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
294+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
295+
}
253296
}
254297

255298
List<BlobPair> copyList = new ArrayList<>();
256299
traverse(BlobId.of(sourcePath.getBucket(), sourcePath.getName()), recursive, sourceBlob -> {
257300
BlobId destBlobID = resolve(sourcePath.getName(), sourceBlob.getBlobId().getName(),
258301
destPath, destinationBaseExists);
259302
if (!overwrite) {
260-
Blob destBlob = storage.get(destBlobID);
303+
Blob destBlob;
304+
try {
305+
destBlob = storage.get(destBlobID);
306+
} catch (Exception e) {
307+
String errorReason = String.format("Unable to access GCS bucket '%s'", destPath.getBucket());
308+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
309+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
310+
}
261311
// we can't just use Blob's isDirectory() because the cloud console will create a 'directory' by creating
262312
// a 0 size placeholder blob that ends with '/'. This placeholder blob's isDirectory() method returns false,
263313
// but we don't want the overwrite check to fail on it. So we explicitly ignore the check for these 0 size
264314
// placeholder blobs.
265315
if (destBlob != null && !destBlob.getName().endsWith("/") && destBlob.getSize() != 0) {
266-
throw new IllegalArgumentException(String.format("%s already exists.", toPath(destBlobID)));
316+
String errorReason = String.format("%s already exists.", toPath(destBlobID));
317+
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
318+
errorReason, errorReason, ErrorType.USER, true, null);
267319
}
268320
}
269321
copyList.add(new BlobPair(sourceBlob, destBlobID));
@@ -347,8 +399,15 @@ static String append(String base, String part) {
347399
* @param consumer the blob consumer
348400
*/
349401
private void traverse(BlobId blobId, boolean recursive, Consumer<Blob> consumer) {
350-
Page<Blob> blobList = storage.list(blobId.getBucket(), Storage.BlobListOption.currentDirectory(),
351-
Storage.BlobListOption.prefix(blobId.getName()));
402+
Page<Blob> blobList;
403+
try {
404+
blobList = storage.list(blobId.getBucket(), Storage.BlobListOption.currentDirectory(),
405+
Storage.BlobListOption.prefix(blobId.getName()));
406+
} catch (Exception e) {
407+
String errorReason = String.format("");
408+
throw GCPErrorDetailsProviderUtil.getHttpResponseExceptionDetailsFromChain(e, errorReason, ErrorType.UNKNOWN,
409+
true, GCPUtils.GCS_SUPPORTED_DOC_URL);
410+
}
352411
for (Blob blob : blobList.iterateAll()) {
353412
if (!blob.isDirectory()) {
354413
consumer.accept(blob);
@@ -363,11 +422,17 @@ private static String toPath(BlobId blobId) {
363422
}
364423

365424
public static StorageClient create(String project, @Nullable String serviceAccount,
366-
Boolean isServiceAccountFilePath, @Nullable Integer readTimeout)
367-
throws IOException {
425+
Boolean isServiceAccountFilePath, @Nullable Integer readTimeout) {
368426
StorageOptions.Builder builder = StorageOptions.newBuilder().setProjectId(project);
369427
if (serviceAccount != null) {
370-
builder.setCredentials(GCPUtils.loadServiceAccountCredentials(serviceAccount, isServiceAccountFilePath));
428+
try {
429+
builder.setCredentials(GCPUtils.loadServiceAccountCredentials(serviceAccount, isServiceAccountFilePath));
430+
} catch (IOException e) {
431+
String errorReason = "Unable to load service account credentials.";
432+
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
433+
errorReason, String.format("%s %s: %s", errorReason, e.getClass().getName(), e.getMessage()),
434+
ErrorType.UNKNOWN, false, null);
435+
}
371436
}
372437
if (readTimeout != null) {
373438
builder.setTransportOptions(HttpTransportOptions.newBuilder().setReadTimeout(readTimeout * 1000).build());
@@ -376,7 +441,7 @@ public static StorageClient create(String project, @Nullable String serviceAccou
376441
return new StorageClient(storage);
377442
}
378443

379-
public static StorageClient create(GCPConnectorConfig config) throws IOException {
444+
public static StorageClient create(GCPConnectorConfig config) {
380445
return create(config.getProject(), config.getServiceAccount(), config.isServiceAccountFilePath(), null);
381446
}
382447

0 commit comments

Comments
 (0)