Browse Source

HUE-9085 [fb] Improve S3 bucket 301 & 400 error message

When retrieving a bucket a 301 error signify that the bucket exists, but
it is in a different region than the one we are connected to. A 400
error can mean a few things, one of which is that we're connected using
V2 and we're trying to access a region that requires V4 signature. V4
signature requires specifying a host or region when connecting.
Jean-Francois Desjeans Gauthier 6 years ago
parent
commit
f9ee6af463
1 changed files with 18 additions and 5 deletions
  1. 18 5
      desktop/libs/aws/src/aws/s3/s3fs.py

+ 18 - 5
desktop/libs/aws/src/aws/s3/s3fs.py

@@ -95,15 +95,30 @@ class S3FileSystem(object):
     self.header_values = headers
 
   def _get_bucket(self, name):
-    return self._s3_connection.get_bucket(name, headers=self.header_values)
+    try:
+      return self._s3_connection.get_bucket(name, headers=self.header_values)
+    except S3ResponseError as e:
+      if e.status == 301 or e.status == 400:
+        raise S3FileSystemException(_('Failed to retrieve bucket "%s" in region "%s" with "%s". Your bucket is in region "%s"') % (name, self._get_location(), e.message or e.reason, self.get_bucket_location(name)))
+      else:
+        raise e
+
+  def get_bucket_location(self, name):
+    try:
+      # We use make_request, because self._s3_connection.get_bucket does not returns headers which contains the bucket location
+      resp = self._s3_connection.make_request('HEAD', name)
+      return resp.getheader('x-amz-bucket-region')
+    except Exception as e:
+      LOG.warn('Failed to fetch bucket "%s" location with "%s"' % (name, e.message or e.reason))
+      return None
 
   def _get_or_create_bucket(self, name):
     try:
       bucket = self._get_bucket(name)
     except BotoClientError as e:
-      raise S3FileSystemException(_('Failed to create bucket named "%s": %s') % (name, e.reason))
+      raise S3FileSystemException(_('Failed to create bucket "%s" with "%s"') % (name, e.message or e.reason))
     except S3ResponseError as e:
-      if e.status == 403 or e.status == 301:
+      if e.status == 403:
         raise S3FileSystemException(_('User is not authorized to access bucket named "%s". '
           'If you are attempting to create a bucket, this bucket name is already reserved.') % name)
       elif e.status == 404:
@@ -111,8 +126,6 @@ class S3FileSystem(object):
         if self._get_location():
           kwargs['location'] = self._get_location()
         bucket = self._create_bucket(name, **kwargs)
-      elif e.status == 400:
-        raise S3FileSystemException(_('Failed to create bucket named "%s": %s') % (name, e.reason))
       else:
         raise S3FileSystemException(e.message or e.reason)
     return bucket