You've already forked mariadb-columnstore-engine
mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-08-07 03:22:57 +03:00
MCOL-4386: Create new StorageManager setting for EC2 using assigned IAM credentials.
This commit is contained in:
@@ -276,13 +276,13 @@ if [ ! -z "$MCS_USE_S3_STORAGE" ] && [ $MCS_USE_S3_STORAGE -eq 1 ]; then
|
|||||||
if [ -z "$MCS_S3_BUCKET" ]; then
|
if [ -z "$MCS_S3_BUCKET" ]; then
|
||||||
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_BUCKET."
|
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_BUCKET."
|
||||||
fi
|
fi
|
||||||
if [ -z "$MCS_S3_ACCESS_KEY_ID" ]; then
|
if [ -z "$MCS_S3_ACCESS_KEY_ID" ] && [ -z "$MCS_S3_ROLE_NAME" ]; then
|
||||||
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_ACCESS_KEY_ID."
|
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_ACCESS_KEY_ID."
|
||||||
fi
|
fi
|
||||||
if [ -z "$MCS_S3_SECRET_ACCESS_KEY" ]; then
|
if [ -z "$MCS_S3_SECRET_ACCESS_KEY" ] && [ -z "$MCS_S3_ROLE_NAME" ]; then
|
||||||
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_SECRET_ACCESS_KEY."
|
echo "Environment variable \$MCS_USE_S3_STORAGE is set but there is no \$MCS_S3_SECRET_ACCESS_KEY."
|
||||||
fi
|
fi
|
||||||
if [ -z "$MCS_S3_BUCKET" ] || [ -z "$MCS_S3_ACCESS_KEY_ID" ] || [ -z "$MCS_S3_SECRET_ACCESS_KEY" ]; then
|
if [ -z "$MCS_S3_BUCKET" ] || [[ -z "$MCS_S3_ACCESS_KEY_ID" && -z "$MCS_S3_ROLE_NAME" ]] || [[ -z "$MCS_S3_SECRET_ACCESS_KEY" && -z "$MCS_S3_ROLE_NAME" ]]; then
|
||||||
echo "Using local storage."
|
echo "Using local storage."
|
||||||
else
|
else
|
||||||
@ENGINE_BINDIR@/mcsSetConfig -d Installation DBRootStorageType "storagemanager"
|
@ENGINE_BINDIR@/mcsSetConfig -d Installation DBRootStorageType "storagemanager"
|
||||||
|
@@ -27,12 +27,28 @@
|
|||||||
#include <boost/uuid/uuid.hpp>
|
#include <boost/uuid/uuid.hpp>
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
#include <boost/uuid/random_generator.hpp>
|
#include <boost/uuid/random_generator.hpp>
|
||||||
|
#define BOOST_SPIRIT_THREADSAFE
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
#include "Utilities.h"
|
#include "Utilities.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace storagemanager
|
namespace storagemanager
|
||||||
{
|
{
|
||||||
|
string tolower(const string &s)
|
||||||
|
{
|
||||||
|
string ret(s);
|
||||||
|
for (uint i = 0; i < ret.length(); i++)
|
||||||
|
ret[i] = ::tolower(ret[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||||
|
{
|
||||||
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool retryable_error(uint8_t s3err)
|
inline bool retryable_error(uint8_t s3err)
|
||||||
{
|
{
|
||||||
@@ -41,6 +57,7 @@ inline bool retryable_error(uint8_t s3err)
|
|||||||
s3err == MS3_ERR_REQUEST_ERROR ||
|
s3err == MS3_ERR_REQUEST_ERROR ||
|
||||||
s3err == MS3_ERR_OOM ||
|
s3err == MS3_ERR_OOM ||
|
||||||
s3err == MS3_ERR_IMPOSSIBLE ||
|
s3err == MS3_ERR_IMPOSSIBLE ||
|
||||||
|
s3err == MS3_ERR_AUTH ||
|
||||||
s3err == MS3_ERR_SERVER ||
|
s3err == MS3_ERR_SERVER ||
|
||||||
s3err == MS3_ERR_AUTH_ROLE
|
s3err == MS3_ERR_AUTH_ROLE
|
||||||
);
|
);
|
||||||
@@ -61,7 +78,8 @@ const int s3err_to_errno[] = {
|
|||||||
EKEYREJECTED, // 8 MS3_ERR_AUTH
|
EKEYREJECTED, // 8 MS3_ERR_AUTH
|
||||||
ENOENT, // 9 MS3_ERR_NOT_FOUND
|
ENOENT, // 9 MS3_ERR_NOT_FOUND
|
||||||
EPROTO, // 10 MS3_ERR_SERVER
|
EPROTO, // 10 MS3_ERR_SERVER
|
||||||
EMSGSIZE // 11 MS3_ERR_TOO_BIG
|
EMSGSIZE, // 11 MS3_ERR_TOO_BIG
|
||||||
|
EKEYREJECTED // 12 MS3_ERR_AUTH_ROLE
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *s3err_msgs[] = {
|
const char *s3err_msgs[] = {
|
||||||
@@ -76,7 +94,8 @@ const char *s3err_msgs[] = {
|
|||||||
"Authentication failed",
|
"Authentication failed",
|
||||||
"Object not found",
|
"Object not found",
|
||||||
"Unknown error code in response",
|
"Unknown error code in response",
|
||||||
"Data to PUT is too large; 4GB maximum length"
|
"Data to PUT is too large; 4GB maximum length",
|
||||||
|
"Authentication failed, token has expired"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -97,33 +116,62 @@ S3Storage::S3Storage(bool skipRetry) : skipRetryableErrors(skipRetry)
|
|||||||
Init an ms3_st object
|
Init an ms3_st object
|
||||||
*/
|
*/
|
||||||
Config *config = Config::get();
|
Config *config = Config::get();
|
||||||
|
|
||||||
const char *keyerr = "S3 access requires setting AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env vars, "
|
const char *keyerr = "S3 access requires setting AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY env vars, "
|
||||||
" or setting aws_access_key_id and aws_secret_access_key in storagemanager.cnf";
|
" or setting aws_access_key_id and aws_secret_access_key, or configure an IAM role with ec2_iam_mode=enabled."
|
||||||
|
" Check storagemanager.cnf file for more information.";
|
||||||
key = config->getValue("S3", "aws_access_key_id");
|
key = config->getValue("S3", "aws_access_key_id");
|
||||||
secret = config->getValue("S3", "aws_secret_access_key");
|
secret = config->getValue("S3", "aws_secret_access_key");
|
||||||
IAMrole = config->getValue("S3", "iam_role_name");
|
IAMrole = config->getValue("S3", "iam_role_name");
|
||||||
STSendpoint = config->getValue("S3", "sts_endpoint");
|
STSendpoint = config->getValue("S3", "sts_endpoint");
|
||||||
STSregion = config->getValue("S3", "sts_region");
|
STSregion = config->getValue("S3", "sts_region");
|
||||||
|
string ec2_mode = tolower(config->getValue("S3", "ec2_iam_mode"));
|
||||||
|
bool keyMissing = false;
|
||||||
|
isEC2Instance = false;
|
||||||
|
ec2iamEnabled = false;
|
||||||
|
|
||||||
|
if (ec2_mode == "enabled")
|
||||||
|
{
|
||||||
|
ec2iamEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (key.empty())
|
if (key.empty())
|
||||||
{
|
{
|
||||||
char *_key_id = getenv("AWS_ACCESS_KEY_ID");
|
char *_key_id = getenv("AWS_ACCESS_KEY_ID");
|
||||||
if (!_key_id)
|
if (!_key_id)
|
||||||
{
|
{
|
||||||
logger->log(LOG_ERR, keyerr);
|
keyMissing = true;
|
||||||
throw runtime_error(keyerr);
|
|
||||||
}
|
}
|
||||||
key = _key_id;
|
else
|
||||||
|
key = _key_id;
|
||||||
}
|
}
|
||||||
if (secret.empty())
|
if (secret.empty())
|
||||||
{
|
{
|
||||||
char *_secret_id = getenv("AWS_SECRET_ACCESS_KEY");
|
char *_secret_id = getenv("AWS_SECRET_ACCESS_KEY");
|
||||||
if (!_secret_id)
|
if (!_secret_id)
|
||||||
|
{
|
||||||
|
keyMissing = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
secret = _secret_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid to not have keys configured if running on ec2 instance.
|
||||||
|
// Attempt to get those credentials from instance.
|
||||||
|
if (keyMissing)
|
||||||
|
{
|
||||||
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
}
|
||||||
|
if (!IAMrole.empty() && getCredentialsFromMetadataEC2())
|
||||||
|
{
|
||||||
|
isEC2Instance = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
logger->log(LOG_ERR, keyerr);
|
logger->log(LOG_ERR, keyerr);
|
||||||
throw runtime_error(keyerr);
|
throw runtime_error(keyerr);
|
||||||
}
|
}
|
||||||
secret = _secret_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
region = config->getValue("S3", "region");
|
region = config->getValue("S3", "region");
|
||||||
@@ -157,6 +205,56 @@ S3Storage::~S3Storage()
|
|||||||
throw runtime_error(msg); \
|
throw runtime_error(msg); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool S3Storage::getIAMRoleFromMetadataEC2()
|
||||||
|
{
|
||||||
|
CURL *curl = NULL;
|
||||||
|
CURLcode curl_res;
|
||||||
|
string readBuffer;
|
||||||
|
string instanceMetadata = "http://169.254.169.254/latest/meta-data/iam/security-credentials/";
|
||||||
|
curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, instanceMetadata.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||||
|
curl_res = curl_easy_perform(curl);
|
||||||
|
if (curl_res != CURLE_OK)
|
||||||
|
{
|
||||||
|
logger->log(LOG_ERR, "CURL fail %u",curl_res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IAMrole = readBuffer;
|
||||||
|
logger->log(LOG_INFO, "S3Storage: IAM Role Name = %s",IAMrole.c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool S3Storage::getCredentialsFromMetadataEC2()
|
||||||
|
{
|
||||||
|
CURL *curl = NULL;
|
||||||
|
CURLcode curl_res;
|
||||||
|
std::string readBuffer;
|
||||||
|
string instanceMetadata = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" + IAMrole;
|
||||||
|
curl = curl_easy_init();
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, instanceMetadata.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||||
|
curl_res = curl_easy_perform(curl);
|
||||||
|
if (curl_res != CURLE_OK)
|
||||||
|
{
|
||||||
|
logger->log(LOG_ERR, "CURL fail %u",curl_res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stringstream credentials(readBuffer);
|
||||||
|
boost::property_tree::ptree pt;
|
||||||
|
boost::property_tree::read_json(credentials, pt);
|
||||||
|
key = pt.get<string>("AccessKeyId");
|
||||||
|
secret = pt.get<string>("SecretAccessKey");
|
||||||
|
token = pt.get<string>("Token");
|
||||||
|
logger->log(LOG_INFO, "S3Storage: key = %s secret = %s token = %s",key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void S3Storage::testConnectivityAndPerms()
|
void S3Storage::testConnectivityAndPerms()
|
||||||
{
|
{
|
||||||
boost::shared_array<uint8_t> testObj(new uint8_t[1]);
|
boost::shared_array<uint8_t> testObj(new uint8_t[1]);
|
||||||
@@ -244,12 +342,18 @@ int S3Storage::getObject(const string &_sourceKey, boost::shared_array<uint8_t>
|
|||||||
if (err && (!skipRetryableErrors && retryable_error(err)))
|
if (err && (!skipRetryableErrors && retryable_error(err)))
|
||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::getObject(): failed to GET, server says '%s'. bucket = %s, key = %s."
|
logger->log(LOG_WARNING, "S3Storage::getObject(): failed to GET, server says '%s'. bucket = %s, key = %s."
|
||||||
" Retrying...", ms3_server_error(creds), bucket.c_str(), sourceKey.c_str());
|
" Retrying...", ms3_server_error(creds), bucket.c_str(), sourceKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::getObject(): failed to GET, got '%s'. bucket = %s, key = %s. Retrying...",
|
logger->log(LOG_WARNING, "S3Storage::getObject(): failed to GET, got '%s'. bucket = %s, key = %s. Retrying...",
|
||||||
s3err_msgs[err], bucket.c_str(), sourceKey.c_str());
|
s3err_msgs[err], bucket.c_str(), sourceKey.c_str());
|
||||||
if(!IAMrole.empty())
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
getCredentialsFromMetadataEC2();
|
||||||
|
ms3_ec2_set_cred(creds,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
ms3_assume_role(creds);
|
ms3_assume_role(creds);
|
||||||
}
|
}
|
||||||
@@ -344,12 +448,18 @@ int S3Storage::putObject(const boost::shared_array<uint8_t> data, size_t len, co
|
|||||||
if (s3err && (!skipRetryableErrors && retryable_error(s3err)))
|
if (s3err && (!skipRetryableErrors && retryable_error(s3err)))
|
||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::putObject(): failed to PUT, server says '%s'. bucket = %s, key = %s."
|
logger->log(LOG_WARNING, "S3Storage::putObject(): failed to PUT, server says '%s'. bucket = %s, key = %s."
|
||||||
" Retrying...", ms3_server_error(creds), bucket.c_str(), destKey.c_str());
|
" Retrying...", ms3_server_error(creds), bucket.c_str(), destKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::putObject(): failed to PUT, got '%s'. bucket = %s, key = %s."
|
logger->log(LOG_WARNING, "S3Storage::putObject(): failed to PUT, got '%s'. bucket = %s, key = %s."
|
||||||
" Retrying...", s3err_msgs[s3err], bucket.c_str(), destKey.c_str());
|
" Retrying...", s3err_msgs[s3err], bucket.c_str(), destKey.c_str());
|
||||||
if(!IAMrole.empty())
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
getCredentialsFromMetadataEC2();
|
||||||
|
ms3_ec2_set_cred(creds,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
ms3_assume_role(creds);
|
ms3_assume_role(creds);
|
||||||
}
|
}
|
||||||
@@ -373,7 +483,7 @@ int S3Storage::putObject(const boost::shared_array<uint8_t> data, size_t len, co
|
|||||||
int S3Storage::deleteObject(const string &_key)
|
int S3Storage::deleteObject(const string &_key)
|
||||||
{
|
{
|
||||||
uint8_t s3err;
|
uint8_t s3err;
|
||||||
string key = prefix + _key;
|
string deleteKey = prefix + _key;
|
||||||
ms3_st *creds = getConnection();
|
ms3_st *creds = getConnection();
|
||||||
if (!creds)
|
if (!creds)
|
||||||
{
|
{
|
||||||
@@ -384,16 +494,22 @@ int S3Storage::deleteObject(const string &_key)
|
|||||||
ScopedConnection sc(this, creds);
|
ScopedConnection sc(this, creds);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
s3err = ms3_delete(creds, bucket.c_str(), key.c_str());
|
s3err = ms3_delete(creds, bucket.c_str(), deleteKey.c_str());
|
||||||
if (s3err && s3err != MS3_ERR_NOT_FOUND && (!skipRetryableErrors && retryable_error(s3err)))
|
if (s3err && s3err != MS3_ERR_NOT_FOUND && (!skipRetryableErrors && retryable_error(s3err)))
|
||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, server says '%s'. bucket = %s, key = %s."
|
logger->log(LOG_WARNING, "S3Storage::deleteObject(): failed to DELETE, server says '%s'. bucket = %s, key = %s."
|
||||||
" Retrying...", ms3_server_error(creds), bucket.c_str(), key.c_str());
|
" Retrying...", ms3_server_error(creds), bucket.c_str(), deleteKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, got '%s'. bucket = %s, key = %s. Retrying...",
|
logger->log(LOG_WARNING, "S3Storage::deleteObject(): failed to DELETE, got '%s'. bucket = %s, key = %s. Retrying...",
|
||||||
s3err_msgs[s3err], bucket.c_str(), key.c_str());
|
s3err_msgs[s3err], bucket.c_str(), deleteKey.c_str());
|
||||||
if(!IAMrole.empty())
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
getCredentialsFromMetadataEC2();
|
||||||
|
ms3_ec2_set_cred(creds,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
ms3_assume_role(creds);
|
ms3_assume_role(creds);
|
||||||
}
|
}
|
||||||
@@ -405,10 +521,10 @@ int S3Storage::deleteObject(const string &_key)
|
|||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, server says '%s'. bucket = %s, key = %s.",
|
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, server says '%s'. bucket = %s, key = %s.",
|
||||||
ms3_server_error(creds), bucket.c_str(), key.c_str());
|
ms3_server_error(creds), bucket.c_str(), deleteKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, got '%s'. bucket = %s, key = %s.",
|
logger->log(LOG_ERR, "S3Storage::deleteObject(): failed to DELETE, got '%s'. bucket = %s, key = %s.",
|
||||||
s3err_msgs[s3err], bucket.c_str(), key.c_str());
|
s3err_msgs[s3err], bucket.c_str(), deleteKey.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -433,12 +549,18 @@ int S3Storage::copyObject(const string &_sourceKey, const string &_destKey)
|
|||||||
if (s3err && (!skipRetryableErrors && retryable_error(s3err)))
|
if (s3err && (!skipRetryableErrors && retryable_error(s3err)))
|
||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::copyObject(): failed to copy, server says '%s'. bucket = %s, srckey = %s, "
|
logger->log(LOG_WARNING, "S3Storage::copyObject(): failed to copy, server says '%s'. bucket = %s, srckey = %s, "
|
||||||
"destkey = %s. Retrying...", ms3_server_error(creds), bucket.c_str(), sourceKey.c_str(), destKey.c_str());
|
"destkey = %s. Retrying...", ms3_server_error(creds), bucket.c_str(), sourceKey.c_str(), destKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::copyObject(): failed to copy, got '%s'. bucket = %s, srckey = %s, "
|
logger->log(LOG_WARNING, "S3Storage::copyObject(): failed to copy, got '%s'. bucket = %s, srckey = %s, "
|
||||||
" destkey = %s. Retrying...", s3err_msgs[s3err], bucket.c_str(), sourceKey.c_str(), destKey.c_str());
|
" destkey = %s. Retrying...", s3err_msgs[s3err], bucket.c_str(), sourceKey.c_str(), destKey.c_str());
|
||||||
if(!IAMrole.empty())
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
getCredentialsFromMetadataEC2();
|
||||||
|
ms3_ec2_set_cred(creds,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
ms3_assume_role(creds);
|
ms3_assume_role(creds);
|
||||||
}
|
}
|
||||||
@@ -475,7 +597,7 @@ int S3Storage::copyObject(const string &_sourceKey, const string &_destKey)
|
|||||||
|
|
||||||
int S3Storage::exists(const string &_key, bool *out)
|
int S3Storage::exists(const string &_key, bool *out)
|
||||||
{
|
{
|
||||||
string key = prefix + _key;
|
string existsKey = prefix + _key;
|
||||||
uint8_t s3err;
|
uint8_t s3err;
|
||||||
ms3_status_st status;
|
ms3_status_st status;
|
||||||
ms3_st *creds = getConnection();
|
ms3_st *creds = getConnection();
|
||||||
@@ -488,16 +610,22 @@ int S3Storage::exists(const string &_key, bool *out)
|
|||||||
ScopedConnection sc(this, creds);
|
ScopedConnection sc(this, creds);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
s3err = ms3_status(creds, bucket.c_str(), key.c_str(), &status);
|
s3err = ms3_status(creds, bucket.c_str(), existsKey.c_str(), &status);
|
||||||
if (s3err && s3err != MS3_ERR_NOT_FOUND && (!skipRetryableErrors && retryable_error(s3err)))
|
if (s3err && s3err != MS3_ERR_NOT_FOUND && (!skipRetryableErrors && retryable_error(s3err)))
|
||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, server says '%s'. bucket = %s, key = %s."
|
logger->log(LOG_WARNING, "S3Storage::exists(): failed to HEAD, server says '%s'. bucket = %s, key = %s."
|
||||||
" Retrying...", ms3_server_error(creds), bucket.c_str(), key.c_str());
|
" Retrying...", ms3_server_error(creds), bucket.c_str(), existsKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, got '%s'. bucket = %s, key = %s. Retrying...",
|
logger->log(LOG_WARNING, "S3Storage::exists(): failed to HEAD, got '%s'. bucket = %s, key = %s. Retrying...",
|
||||||
s3err_msgs[s3err], bucket.c_str(), key.c_str());
|
s3err_msgs[s3err], bucket.c_str(), existsKey.c_str());
|
||||||
if(!IAMrole.empty())
|
if (ec2iamEnabled)
|
||||||
|
{
|
||||||
|
getIAMRoleFromMetadataEC2();
|
||||||
|
getCredentialsFromMetadataEC2();
|
||||||
|
ms3_ec2_set_cred(creds,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
ms3_assume_role(creds);
|
ms3_assume_role(creds);
|
||||||
}
|
}
|
||||||
@@ -509,10 +637,10 @@ int S3Storage::exists(const string &_key, bool *out)
|
|||||||
{
|
{
|
||||||
if (ms3_server_error(creds))
|
if (ms3_server_error(creds))
|
||||||
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, server says '%s'. bucket = %s, key = %s.",
|
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, server says '%s'. bucket = %s, key = %s.",
|
||||||
ms3_server_error(creds), bucket.c_str(), key.c_str());
|
ms3_server_error(creds), bucket.c_str(), existsKey.c_str());
|
||||||
else
|
else
|
||||||
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, got '%s'. bucket = %s, key = %s.",
|
logger->log(LOG_ERR, "S3Storage::exists(): failed to HEAD, got '%s'. bucket = %s, key = %s.",
|
||||||
s3err_msgs[s3err], bucket.c_str(), key.c_str());
|
s3err_msgs[s3err], bucket.c_str(), existsKey.c_str());
|
||||||
errno = s3err_to_errno[s3err];
|
errno = s3err_to_errno[s3err];
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -552,9 +680,17 @@ ms3_st * S3Storage::getConnection()
|
|||||||
logger->log(LOG_ERR, "S3Storage::getConnection(): ms3_init returned NULL, no specific info to report");
|
logger->log(LOG_ERR, "S3Storage::getConnection(): ms3_init returned NULL, no specific info to report");
|
||||||
if(!IAMrole.empty())
|
if(!IAMrole.empty())
|
||||||
{
|
{
|
||||||
res = ms3_init_assume_role(ret, (IAMrole.empty() ? NULL : IAMrole.c_str()),
|
if (isEC2Instance)
|
||||||
(STSendpoint.empty() ? NULL : STSendpoint.c_str()),
|
{
|
||||||
(STSregion.empty() ? NULL : STSregion.c_str()));
|
res = ms3_ec2_set_cred(ret,IAMrole.c_str(),key.c_str(),secret.c_str(),token.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = ms3_init_assume_role(ret, (IAMrole.empty() ? NULL : IAMrole.c_str()),
|
||||||
|
(STSendpoint.empty() ? NULL : STSendpoint.c_str()),
|
||||||
|
(STSregion.empty() ? NULL : STSregion.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
// Something is wrong with the assume role so abort as if the ms3_init failed
|
// Something is wrong with the assume role so abort as if the ms3_init failed
|
||||||
|
@@ -23,6 +23,8 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include "CloudStorage.h"
|
#include "CloudStorage.h"
|
||||||
#include "libmarias3/marias3.h"
|
#include "libmarias3/marias3.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
namespace storagemanager
|
namespace storagemanager
|
||||||
{
|
{
|
||||||
@@ -43,6 +45,8 @@ class S3Storage : public CloudStorage
|
|||||||
int exists(const std::string &key, bool *out);
|
int exists(const std::string &key, bool *out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool getIAMRoleFromMetadataEC2();
|
||||||
|
bool getCredentialsFromMetadataEC2();
|
||||||
void testConnectivityAndPerms();
|
void testConnectivityAndPerms();
|
||||||
ms3_st *getConnection();
|
ms3_st *getConnection();
|
||||||
void returnConnection(ms3_st *);
|
void returnConnection(ms3_st *);
|
||||||
@@ -54,10 +58,13 @@ class S3Storage : public CloudStorage
|
|||||||
std::string region;
|
std::string region;
|
||||||
std::string key;
|
std::string key;
|
||||||
std::string secret;
|
std::string secret;
|
||||||
|
std::string token;
|
||||||
std::string endpoint;
|
std::string endpoint;
|
||||||
std::string IAMrole;
|
std::string IAMrole;
|
||||||
std::string STSendpoint;
|
std::string STSendpoint;
|
||||||
std::string STSregion;
|
std::string STSregion;
|
||||||
|
bool isEC2Instance;
|
||||||
|
bool ec2iamEnabled;
|
||||||
|
|
||||||
struct Connection
|
struct Connection
|
||||||
{
|
{
|
||||||
|
@@ -125,6 +125,12 @@ bucket = some_bucket
|
|||||||
# sts_region =
|
# sts_region =
|
||||||
# sts_endpoint =
|
# sts_endpoint =
|
||||||
|
|
||||||
|
# If running on AWS EC2 instance the value ec2_iam_mode can be set
|
||||||
|
# 'enabled' and allow StorageManager to detect IAM role assigned
|
||||||
|
# to EC2 instances. This will then use the the temporary credentials
|
||||||
|
# provided by EC2 metadata for S3 authentication access/secret keys.
|
||||||
|
# ec2_iam_mode=enabled
|
||||||
|
|
||||||
# The LocalStorage section configures the 'local storage' module
|
# The LocalStorage section configures the 'local storage' module
|
||||||
# if specified by ObjectStorage/service.
|
# if specified by ObjectStorage/service.
|
||||||
[LocalStorage]
|
[LocalStorage]
|
||||||
|
Reference in New Issue
Block a user