Retry BucketCheck containing directory paths

This commit is contained in:
Takeshi Nakatani 2023-01-05 10:06:20 +00:00 committed by Andrew Gaul
parent e4f85c1e08
commit 16bc44948e
3 changed files with 60 additions and 13 deletions

View File

@ -3514,10 +3514,13 @@ int S3fsCurl::GetObjectRequest(const char* tpath, int fd, off_t start, off_t siz
return result;
}
int S3fsCurl::CheckBucket()
int S3fsCurl::CheckBucket(const char* check_path)
{
S3FS_PRN_INFO3("check a bucket.");
if(!check_path || 0 == strlen(check_path)){
return -EIO;
}
if(!CreateCurlHandle()){
return -EIO;
}
@ -3526,13 +3529,14 @@ int S3fsCurl::CheckBucket()
query_string = "list-type=2";
urlargs = "?" + query_string;
}
std::string resource;
std::string turl;
MakeUrlResource("/", resource, turl);
MakeUrlResource(check_path, resource, turl);
turl += urlargs;
url = prepare_url(turl.c_str());
path = "/"; // Only check the presence of the bucket, not the entire virtual path.
path = check_path;
requestHeaders = NULL;
responseHeaders.clear();
bodydata.Clear();

View File

@ -352,7 +352,7 @@ class S3fsCurl
int PutRequest(const char* tpath, headers_t& meta, int fd);
int PreGetObjectRequest(const char* tpath, int fd, off_t start, off_t size, sse_type_t ssetype, const std::string& ssevalue);
int GetObjectRequest(const char* tpath, int fd, off_t start = -1, off_t size = -1);
int CheckBucket();
int CheckBucket(const char* check_path);
int ListBucketRequest(const char* tpath, const char* query);
int PreMultipartPostRequest(const char* tpath, headers_t& meta, std::string& upload_id, bool is_copy);
int CompleteMultipartPostRequest(const char* tpath, const std::string& upload_id, etaglist_t& parts);

View File

@ -4029,6 +4029,30 @@ static bool check_endpoint_error(const char* pbody, size_t len, std::string& exp
return true;
}
// [NOTE]
// This checks whether access to the bucket when s3fs is started.
//
// The following patterns for mount point are supported by s3fs:
// (1) Mount the bucket top
// (2) Mount the directory(folder) under the bucket. In this case, there are
// the following cases:
// (2A) Directories created by clients other than s3fs
// (2B) Directory created by s3fs
//
// At first in this functoin, if user has access to the bucket, the checking
// access to the bucket succeeds and this function returns success. However,
// if user does not have access to the bucket and has permissions to the
// directory, this first check will fail.
// But if user specifies the directory for mount point, this function retries
// to check with the path containing the directory. And it will be success.
//
// In the case of (2A), the check will succeed if the bucket allows to access,
// but will fail if permissions are granted only to the directory, as it is not
// a directory recognized by s3fs. This combination is not supported by s3fs,
// so make sure user create the directory before starting s3fs.
// In case (2B), if user does not have access to bucket, the first check(to
// bucket) fails, but the retry check(with path) succeeds.
//
static int s3fs_check_service()
{
S3FS_PRN_INFO("check services.");
@ -4041,9 +4065,10 @@ static int s3fs_check_service()
S3fsCurl s3fscurl;
int res;
if(0 > (res = s3fscurl.CheckBucket())){
if(0 > (res = s3fscurl.CheckBucket("/"))){
// get response code
long responseCode = s3fscurl.GetLastResponseCode();
long responseCode = s3fscurl.GetLastResponseCode();
bool changed_endpoint = false;
// check wrong endpoint, and automatically switch endpoint
if(300 <= responseCode && responseCode < 500){
@ -4066,7 +4091,9 @@ static int s3fs_check_service()
}else{
// current endpoint is wrong, so try to connect to expected region.
S3FS_PRN_CRIT("Failed to connect region '%s'(default), so retry to connect region '%s'.", endpoint.c_str(), expectregion.c_str());
endpoint = expectregion;
endpoint = expectregion;
changed_endpoint = true;
if(S3fsCurl::GetSignatureType() == V4_ONLY ||
S3fsCurl::GetSignatureType() == V2_OR_V4){
if(s3host == "http://s3.amazonaws.com"){
@ -4075,11 +4102,6 @@ static int s3fs_check_service()
s3host = "https://s3-" + endpoint + ".amazonaws.com";
}
}
// retry to check with new endpoint
s3fscurl.DestroyCurlHandle();
res = s3fscurl.CheckBucket();
responseCode = s3fscurl.GetLastResponseCode();
}
}else if(check_endpoint_error(body->str(), body->size(), expectendpoint)){
S3FS_PRN_ERR("S3 service returned PermanentRedirect with endpoint: %s", expectendpoint.c_str());
@ -4087,6 +4109,20 @@ static int s3fs_check_service()
}
}
// retry to check with new endpoint
if(changed_endpoint){
s3fscurl.DestroyCurlHandle();
res = s3fscurl.CheckBucket("/");
responseCode = s3fscurl.GetLastResponseCode();
}
// retry to check with mount prefix
if(300 <= responseCode && responseCode < 500 && !mount_prefix.empty()){
s3fscurl.DestroyCurlHandle();
res = s3fscurl.CheckBucket(get_realpath("/").c_str());
responseCode = s3fscurl.GetLastResponseCode();
}
// try signature v2
if(0 > res && (responseCode == 400 || responseCode == 403) && S3fsCurl::GetSignatureType() == V2_OR_V4){
// switch sigv2
@ -4095,8 +4131,15 @@ static int s3fs_check_service()
// retry to check with sigv2
s3fscurl.DestroyCurlHandle();
res = s3fscurl.CheckBucket();
res = s3fscurl.CheckBucket("/");
responseCode = s3fscurl.GetLastResponseCode();
// retry to check with mount prefix
if(300 <= responseCode && responseCode < 500 && !mount_prefix.empty()){
s3fscurl.DestroyCurlHandle();
res = s3fscurl.CheckBucket(get_realpath("/").c_str());
responseCode = s3fscurl.GetLastResponseCode();
}
}
// check errors(after retrying)