28
28
import com .google .cloud .storage .StorageException ;
29
29
import com .google .cloud .storage .StorageOptions ;
30
30
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 ;
31
34
import io .cdap .plugin .gcp .common .GCPConnectorConfig ;
35
+ import io .cdap .plugin .gcp .common .GCPErrorDetailsProviderUtil ;
32
36
import io .cdap .plugin .gcp .common .GCPUtils ;
33
37
import org .slf4j .Logger ;
34
38
import org .slf4j .LoggerFactory ;
@@ -68,7 +72,14 @@ public Blob pickABlob(String path) {
68
72
return null ;
69
73
}
70
74
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
+ }
72
83
Iterator <Blob > iterator = blobPage .getValues ().iterator ();
73
84
while (iterator .hasNext ()) {
74
85
Blob blob = iterator .next ();
@@ -89,7 +100,13 @@ public void setMetaData(Blob blob, Map<String, String> metaData) {
89
100
if (blob == null || metaData == null || metaData .isEmpty ()) {
90
101
return ;
91
102
}
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
+ }
93
110
}
94
111
95
112
/**
@@ -102,7 +119,14 @@ public void mapMetaDataForAllBlobs(String path, Consumer<Map<String, String>> fu
102
119
return ;
103
120
}
104
121
GCSPath gcsPath = GCSPath .from (path );
105
- Page <Blob > blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
122
+ Page <Blob > blobPage ;
123
+ try {
124
+ blobPage = storage .list (gcsPath .getBucket (), Storage .BlobListOption .prefix (gcsPath .getName ()));
125
+ } catch (Exception e ) {
126
+ String errorReason = String .format ("Unable to list objects in bucket %s." , gcsPath .getBucket ());
127
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
128
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
129
+ }
106
130
Iterator <Blob > blobIterator = blobPage .iterateAll ().iterator ();
107
131
while (blobIterator .hasNext ()) {
108
132
Blob blob = blobIterator .next ();
@@ -132,9 +156,11 @@ public void createBucketIfNotExists(GCSPath path, @Nullable String location, @Nu
132
156
LOG .warn ("Getting 409 Conflict: {} Bucket at destination path {} may already exist." ,
133
157
e .getMessage (), path .getUri ());
134
158
} else {
135
- throw new RuntimeException (
159
+ String errorReason =
136
160
String .format ("Unable to create bucket %s. Ensure you entered the correct bucket path and " +
137
- "have permissions for it." , path .getBucket ()), e );
161
+ "have permissions for it." , path .getBucket ());
162
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
163
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
138
164
}
139
165
}
140
166
}
@@ -173,9 +199,16 @@ public void move(GCSPath sourcePath, GCSPath destPath, boolean recursive, boolea
173
199
* Get all the matching wildcard paths given the regex input.
174
200
*/
175
201
public List <GCSPath > getMatchedPaths (GCSPath sourcePath , boolean recursive , Pattern wildcardRegex ) {
176
- Page <Blob > blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
202
+ Page <Blob > blobPage ;
203
+ try {
204
+ blobPage = storage .list (sourcePath .getBucket (), Storage .BlobListOption .prefix (
177
205
getWildcardPathPrefix (sourcePath , wildcardRegex )
178
- ));
206
+ ));
207
+ } catch (Exception e ) {
208
+ String errorReason = String .format ("Unable to list objects in bucket %s." , sourcePath .getBucket ());
209
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
210
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
211
+ }
179
212
List <String > blobPageNames = new ArrayList <>();
180
213
blobPage .getValues ().forEach (blob -> blobPageNames .add (blob .getName ()));
181
214
return getFilterMatchedPaths (sourcePath , blobPageNames , recursive );
@@ -212,58 +245,84 @@ static List<GCSPath> getFilterMatchedPaths(GCSPath sourcePath, List<String> blob
212
245
private void pairTraverse (GCSPath sourcePath , GCSPath destPath , boolean recursive , boolean overwrite ,
213
246
Consumer <BlobPair > consumer ) {
214
247
215
- Bucket sourceBucket = null ;
248
+ Bucket sourceBucket ;
216
249
try {
217
250
sourceBucket = storage .get (sourcePath .getBucket ());
218
- } catch (StorageException e ) {
251
+ } catch (Exception e ) {
219
252
// 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 );
253
+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , sourcePath . getBucket ());
254
+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
255
+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
223
256
}
224
257
if (sourceBucket == null ) {
225
- throw new IllegalArgumentException (
226
- String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ()));
258
+ String errorReason = String .format ("Source bucket '%s' does not exist." , sourcePath .getBucket ());
259
+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
260
+ errorReason , errorReason , ErrorType .USER , true , null );
227
261
}
228
- Bucket destBucket = null ;
262
+ Bucket destBucket ;
229
263
try {
230
264
destBucket = storage .get (destPath .getBucket ());
231
- } catch (StorageException e ) {
265
+ } catch (Exception e ) {
232
266
// 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 );
267
+ String errorReason = String . format ( "Unable to access GCS bucket '%s'" , destPath . getBucket ());
268
+ throw GCPErrorDetailsProviderUtil . getHttpResponseExceptionDetailsFromChain ( e , errorReason , ErrorType . UNKNOWN ,
269
+ true , GCPUtils . GCS_SUPPORTED_DOC_URL );
236
270
}
237
271
if (destBucket == null ) {
238
- throw new IllegalArgumentException (
239
- String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ()));
272
+ String errorReason =
273
+ String .format ("Destination bucket '%s' does not exist. Please create it first." , destPath .getBucket ());
274
+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
275
+ errorReason , errorReason , ErrorType .USER , true , null );
240
276
}
241
277
242
278
boolean destinationBaseExists ;
243
279
String baseDestName = destPath .getName ();
244
- if (destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ) {
280
+ boolean destinationBlobExists ;
281
+ try {
282
+ destinationBlobExists = destPath .isBucket () || storage .get (BlobId .of (destPath .getBucket (), baseDestName )) != null ;
283
+ } catch (Exception e ) {
284
+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
285
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
286
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
287
+ }
288
+ if (destinationBlobExists ) {
245
289
destinationBaseExists = true ;
246
290
} else {
247
291
// if gs://bucket2/subdir doesn't exist, check if gs://bucket2/subdir/ exists
248
292
// similarly, if gs://bucket2/subdir/ doesn't exist, check if gs://bucket2/subdir exists
249
293
// this is because "cp dir0 subdir" and "cp dir0 subdir/" are equivalent if the 'subdir' directory exists
250
294
String modifiedName = baseDestName .endsWith ("/" ) ?
251
295
baseDestName .substring (0 , baseDestName .length () - 1 ) : baseDestName + "/" ;
252
- destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
296
+ try {
297
+ destinationBaseExists = storage .get (BlobId .of (destPath .getBucket (), modifiedName )) != null ;
298
+ } catch (Exception e ) {
299
+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
300
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
301
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
302
+ }
253
303
}
254
304
255
305
List <BlobPair > copyList = new ArrayList <>();
256
306
traverse (BlobId .of (sourcePath .getBucket (), sourcePath .getName ()), recursive , sourceBlob -> {
257
307
BlobId destBlobID = resolve (sourcePath .getName (), sourceBlob .getBlobId ().getName (),
258
308
destPath , destinationBaseExists );
259
309
if (!overwrite ) {
260
- Blob destBlob = storage .get (destBlobID );
310
+ Blob destBlob ;
311
+ try {
312
+ destBlob = storage .get (destBlobID );
313
+ } catch (Exception e ) {
314
+ String errorReason = String .format ("Unable to access GCS bucket '%s'" , destPath .getBucket ());
315
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
316
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
317
+ }
261
318
// we can't just use Blob's isDirectory() because the cloud console will create a 'directory' by creating
262
319
// a 0 size placeholder blob that ends with '/'. This placeholder blob's isDirectory() method returns false,
263
320
// but we don't want the overwrite check to fail on it. So we explicitly ignore the check for these 0 size
264
321
// placeholder blobs.
265
322
if (destBlob != null && !destBlob .getName ().endsWith ("/" ) && destBlob .getSize () != 0 ) {
266
- throw new IllegalArgumentException (String .format ("%s already exists." , toPath (destBlobID )));
323
+ String errorReason = String .format ("%s already exists." , toPath (destBlobID ));
324
+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
325
+ errorReason , errorReason , ErrorType .USER , true , null );
267
326
}
268
327
}
269
328
copyList .add (new BlobPair (sourceBlob , destBlobID ));
@@ -347,8 +406,15 @@ static String append(String base, String part) {
347
406
* @param consumer the blob consumer
348
407
*/
349
408
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 ()));
409
+ Page <Blob > blobList ;
410
+ try {
411
+ blobList = storage .list (blobId .getBucket (), Storage .BlobListOption .currentDirectory (),
412
+ Storage .BlobListOption .prefix (blobId .getName ()));
413
+ } catch (Exception e ) {
414
+ String errorReason = String .format ("" );
415
+ throw GCPErrorDetailsProviderUtil .getHttpResponseExceptionDetailsFromChain (e , errorReason , ErrorType .UNKNOWN ,
416
+ true , GCPUtils .GCS_SUPPORTED_DOC_URL );
417
+ }
352
418
for (Blob blob : blobList .iterateAll ()) {
353
419
if (!blob .isDirectory ()) {
354
420
consumer .accept (blob );
@@ -363,11 +429,17 @@ private static String toPath(BlobId blobId) {
363
429
}
364
430
365
431
public static StorageClient create (String project , @ Nullable String serviceAccount ,
366
- Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout )
367
- throws IOException {
432
+ Boolean isServiceAccountFilePath , @ Nullable Integer readTimeout ) {
368
433
StorageOptions .Builder builder = StorageOptions .newBuilder ().setProjectId (project );
369
434
if (serviceAccount != null ) {
370
- builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
435
+ try {
436
+ builder .setCredentials (GCPUtils .loadServiceAccountCredentials (serviceAccount , isServiceAccountFilePath ));
437
+ } catch (IOException e ) {
438
+ String errorReason = "Unable to load service account credentials." ;
439
+ throw ErrorUtils .getProgramFailureException (new ErrorCategory (ErrorCategory .ErrorCategoryEnum .PLUGIN ),
440
+ errorReason , String .format ("%s %s: %s" , errorReason , e .getClass ().getName (), e .getMessage ()),
441
+ ErrorType .UNKNOWN , false , null );
442
+ }
371
443
}
372
444
if (readTimeout != null ) {
373
445
builder .setTransportOptions (HttpTransportOptions .newBuilder ().setReadTimeout (readTimeout * 1000 ).build ());
@@ -376,7 +448,7 @@ public static StorageClient create(String project, @Nullable String serviceAccou
376
448
return new StorageClient (storage );
377
449
}
378
450
379
- public static StorageClient create (GCPConnectorConfig config ) throws IOException {
451
+ public static StorageClient create (GCPConnectorConfig config ) {
380
452
return create (config .getProject (), config .getServiceAccount (), config .isServiceAccountFilePath (), null );
381
453
}
382
454
0 commit comments