Skip to content

add user agent business metric for account id endpoints #3381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,13 @@ namespace Aws

DynamoDBClientConfiguration(const DynamoDBClientConfiguration& other)
: Aws::Client::GenericClientConfiguration(other),
enableEndpointDiscovery(BaseClientConfigClass::enableEndpointDiscovery),
accountId{other.accountId},
accountIdEndpointMode{other.accountIdEndpointMode}
enableEndpointDiscovery(BaseClientConfigClass::enableEndpointDiscovery)
{
}

DynamoDBClientConfiguration(DynamoDBClientConfiguration&& other) noexcept
: Aws::Client::GenericClientConfiguration(std::move(other)),
enableEndpointDiscovery(BaseClientConfigClass::enableEndpointDiscovery),
accountId{std::move(other.accountId)},
accountIdEndpointMode{std::move(other.accountIdEndpointMode)}
enableEndpointDiscovery(BaseClientConfigClass::enableEndpointDiscovery)
{
}

Expand All @@ -40,8 +36,6 @@ namespace Aws
if (this == &other)
return *this;
Aws::Client::GenericClientConfiguration::operator =(other);
accountId = other.accountId;
accountIdEndpointMode = other.accountIdEndpointMode;
return *this;
}

Expand All @@ -50,8 +44,6 @@ namespace Aws
if (this == &other)
return *this;
Aws::Client::GenericClientConfiguration::operator =(std::move(other));
accountId = std::move(other.accountId);
accountIdEndpointMode = std::move(other.accountIdEndpointMode);
return *this;
}

Expand Down Expand Up @@ -90,14 +82,6 @@ namespace Aws
*/
Aws::Crt::Optional<bool>& enableEndpointDiscovery;

/**
* The AWS AccountId used for the request.
*/
Aws::String accountId;
/**
* The AccountId Endpoint Mode.
*/
Aws::String accountIdEndpointMode = "preferred";
private:
void LoadDynamoDBSpecificConfig(const Aws::String& profileName);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,6 @@ void DynamoDBClientConfiguration::LoadDynamoDBSpecificConfig(const Aws::String&
if(!enableEndpointDiscovery) {
enableEndpointDiscovery = IsEndpointDiscoveryEnabled(this->endpointOverride, inputProfileName);
}
// accountId is intentionally not set here: AWS_ACCOUNT_ID env variable may not match the provided credentials.
// it must be set by an auth provider / identity resolver or by an SDK user.
static const char AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE[] = "AWS_ACCOUNT_ID_ENDPOINT_MODE";
static const char AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION[] = "account_id_endpoint_mode";
accountIdEndpointMode = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE,
inputProfileName,
AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION,
{"required", "disabled", "preferred"}, /* allowed values */
"preferred" /* default value */);
}

DynamoDBClientConfiguration::DynamoDBClientConfiguration(const Client::ClientConfigurationInitValues &configuration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,6 @@ namespace Aws
{
using BaseClientConfigClass = Aws::Client::GenericClientConfiguration;

S3ControlClientConfiguration(const S3ControlClientConfiguration& other)
: Aws::Client::GenericClientConfiguration(other),
accountId{other.accountId}
{
}

S3ControlClientConfiguration(S3ControlClientConfiguration&& other) noexcept
: Aws::Client::GenericClientConfiguration(std::move(other)),
accountId{std::move(other.accountId)}
{
}

S3ControlClientConfiguration& operator=(const S3ControlClientConfiguration& other)
{
if (this == &other)
return *this;
Aws::Client::GenericClientConfiguration::operator =(other);
accountId = other.accountId;
return *this;
}

S3ControlClientConfiguration& operator=(S3ControlClientConfiguration&& other) noexcept
{
if (this == &other)
return *this;
Aws::Client::GenericClientConfiguration::operator =(std::move(other));
accountId = std::move(other.accountId);
return *this;
}

S3ControlClientConfiguration(const Client::ClientConfigurationInitValues &configuration = {});

/**
Expand All @@ -72,10 +42,6 @@ namespace Aws
S3ControlClientConfiguration(const Client::ClientConfiguration& config);
bool useArnRegion = false;
Client::AWSAuthV4Signer::PayloadSigningPolicy payloadSigningPolicy = Client::AWSAuthV4Signer::PayloadSigningPolicy::RequestDependent;
/**
* The Account ID used to send the request. This is an optional parameter that will be set automatically for operations that require it.
*/
Aws::String accountId;
private:
void LoadS3ControlSpecificConfig(const Aws::String& profileName);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ void S3ControlClientConfiguration::LoadS3ControlSpecificConfig(const Aws::String
{
useArnRegion = true;
}
// accountId is intentionally not set here: AWS_ACCOUNT_ID env variable may not match the provided credentials.
// it must be set by an auth provider / identity resolver or by an SDK user.
}

S3ControlClientConfiguration::S3ControlClientConfiguration(const Client::ClientConfigurationInitValues &configuration)
Expand Down
10 changes: 10 additions & 0 deletions src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,16 @@ namespace Aws
*/
bool useAnonymousAuth = false;
} winHTTPOptions;

/**
* The AWS AccountId used for the request.
*/
Aws::String accountId;

/**
* The AccountId Endpoint Mode.
*/
Aws::String accountIdEndpointMode = "preferred";
};

/**
Expand Down
4 changes: 4 additions & 0 deletions src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ enum class UserAgentFeature {
FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED,
FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED,
FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED,
ACCOUNT_ID_MODE_PREFERRED,
ACCOUNT_ID_MODE_DISABLED,
ACCOUNT_ID_MODE_REQUIRED,
RESOLVED_ACCOUNT_ID,
};

class AWS_CORE_API UserAgent {
Expand Down
26 changes: 7 additions & 19 deletions src/aws-cpp-sdk-core/include/smithy/client/AwsSmithyClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,32 +346,20 @@ namespace client
ResponseT,
ErrorMarshallerT>>;

/**
* SFINAE implementation for refreshing client context params enabled if the client configuration
* type has a AccountId member. If there is a corresponding member we want to use that in the endpoint
* calculation and set it as a client context parameter.
*/
template <typename T, typename = void>
struct HasAccountId : std::false_type {};

template<typename T>
struct HasAccountId<T, decltype(void(std::declval<T>().accountId))> : std::true_type {};

template<typename ConfigT = ServiceClientConfigurationT, typename std::enable_if<HasAccountId<ConfigT>::value, int>::type = 0>
GetContextEndpointParametersOutcome GetContextEndpointParametersImpl(const AwsSmithyClientAsyncRequestContext& ctx) const {
Aws::Vector<Aws::Endpoint::EndpointParameter> endpointParameters;
const auto resolvedAccountId = ctx.m_awsIdentity->accountId();
if (resolvedAccountId.has_value() && !resolvedAccountId.value().empty() && m_clientConfiguration.accountId.empty()) {
const auto resolvedNonEmptyAccountId = resolvedAccountId.has_value() && !resolvedAccountId.value().empty();
// Set user agent if account ID was resolved in identity provider
if (resolvedNonEmptyAccountId) {
ctx.m_pRequest->AddUserAgentFeature(Aws::Client::UserAgentFeature::RESOLVED_ACCOUNT_ID);
}
// Only set EP param if client configuration does not have a configured account ID and we resolved a account id
if (resolvedNonEmptyAccountId && m_clientConfiguration.accountId.empty()) {
endpointParameters.emplace_back("AccountId", resolvedAccountId.value(), Aws::Endpoint::EndpointParameter::ParameterOrigin::OPERATION_CONTEXT);
}
return endpointParameters;
}

template<typename ConfigT = ServiceClientConfigurationT, typename std::enable_if<!HasAccountId<ConfigT>::value, int>::type = 0>
GetContextEndpointParametersOutcome GetContextEndpointParametersImpl(const AwsSmithyClientAsyncRequestContext& ctx) const {
AWS_UNREFERENCED_PARAM(ctx);
return Aws::Vector<Aws::Endpoint::EndpointParameter>{};
}
};

} // namespace client
Expand Down
18 changes: 14 additions & 4 deletions src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ static const char* REQUEST_MIN_COMPRESSION_SIZE_BYTES_CONFIG_VAR = "request_min_
static const char* AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV";
static const char* DISABLE_IMDSV1_CONFIG_VAR = "AWS_EC2_METADATA_V1_DISABLED";
static const char* DISABLE_IMDSV1_ENV_VAR = "ec2_metadata_v1_disabled";
static const char* AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE = "AWS_ACCOUNT_ID_ENDPOINT_MODE";
static const char* AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION = "account_id_endpoint_mode";

using RequestChecksumConfigurationEnumMapping = std::pair<const char*, RequestChecksumCalculation>;
static const std::array<RequestChecksumConfigurationEnumMapping, 2> REQUEST_CHECKSUM_CONFIG_MAPPING = {{
Expand Down Expand Up @@ -278,12 +280,21 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config)
if (disableIMDSv1 == "true") {
config.disableImdsV1 = true;
}

// accountId is intentionally not set here: AWS_ACCOUNT_ID env variable may not match the provided credentials.
// it must be set by an auth provider / identity resolver or by an SDK user.
config.accountIdEndpointMode = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE,
config.profileName,
AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION,
{"required", "disabled", "preferred"}, /* allowed values */
"preferred" /* default value */);
}

ClientConfiguration::ClientConfiguration()
{
this->disableIMDS = false;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);;

if (!this->disableIMDS &&
region.empty() &&
Expand All @@ -300,13 +311,13 @@ ClientConfiguration::ClientConfiguration()
return;
}
region = Aws::String(Aws::Region::US_EAST_1);
setConfigFromEnvOrProfile(*this);
}

ClientConfiguration::ClientConfiguration(const ClientConfigurationInitValues &configuration)
{
this->disableIMDS = configuration.shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);

if (!this->disableIMDS &&
region.empty() &&
Expand All @@ -323,7 +334,6 @@ ClientConfiguration::ClientConfiguration(const ClientConfigurationInitValues &co
return;
}
region = Aws::String(Aws::Region::US_EAST_1);
setConfigFromEnvOrProfile(*this);
}

ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisableIMDS)
Expand All @@ -333,6 +343,7 @@ ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisable
this->profileName = Aws::String(profile);
}
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);
// Call EC2 Instance Metadata service only once
Aws::String ec2MetadataRegion;
bool hasEc2MetadataRegion = false;
Expand Down Expand Up @@ -368,13 +379,13 @@ ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisable
}

AWS_LOGSTREAM_WARN(CLIENT_CONFIG_TAG, "User specified profile: [" << profile << "] is not found, will use the SDK resolved one.");
setConfigFromEnvOrProfile(*this);
}

ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char* defaultMode, bool shouldDisableIMDS)
{
this->disableIMDS = shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);

// Call EC2 Instance Metadata service only once
Aws::String ec2MetadataRegion;
Expand All @@ -397,7 +408,6 @@ ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char*
}

Aws::Config::Defaults::SetSmartDefaultsConfigurationParameters(*this, defaultMode, hasEc2MetadataRegion, ec2MetadataRegion);
setConfigFromEnvOrProfile(*this);
}

std::shared_ptr<RetryStrategy> InitRetryStrategy(Aws::String retryMode)
Expand Down
28 changes: 27 additions & 1 deletion src/aws-cpp-sdk-core/source/client/UserAgent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>
#include <aws/crt/Config.h>
#include <aws/crt/Optional.h>

#include <iterator>
#include <numeric>
#include <utility>

Expand All @@ -33,7 +35,11 @@ const std::pair<UserAgentFeature, const char*> BUSINESS_METRIC_MAPPING[] = {
{UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_WHEN_SUPPORTED, "Z"},
{UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED, "a"},
{UserAgentFeature::FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED, "b"},
{UserAgentFeature::FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED, "c"}
{UserAgentFeature::FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED, "c"},
{UserAgentFeature::ACCOUNT_ID_MODE_PREFERRED, "P"},
{UserAgentFeature::ACCOUNT_ID_MODE_DISABLED , "Q"},
{UserAgentFeature::ACCOUNT_ID_MODE_REQUIRED, "R"},
{UserAgentFeature::RESOLVED_ACCOUNT_ID, "T"},
};

Aws::String BusinessMetricForFeature(UserAgentFeature feature) {
Expand All @@ -53,6 +59,22 @@ const std::pair<const char*, UserAgentFeature> RETRY_FEATURE_MAPPING[] = {
{"adaptive", UserAgentFeature::RETRY_MODE_ADAPTIVE},
};

const std::pair<const char*, UserAgentFeature> ACCOUNT_ID_MODE_MAPPING[] = {
{"preferred", UserAgentFeature::ACCOUNT_ID_MODE_PREFERRED},
{"disabled", UserAgentFeature::ACCOUNT_ID_MODE_DISABLED},
{"required", UserAgentFeature::ACCOUNT_ID_MODE_REQUIRED},
};

Aws::Crt::Optional<UserAgentFeature> BusinessMetricForAccountIdMode(const Aws::String& accountIdMode) {
const auto *const accountIdFeature = std::find_if(std::begin(ACCOUNT_ID_MODE_MAPPING),
std::end(ACCOUNT_ID_MODE_MAPPING),
[&accountIdMode](const std::pair<const char*, UserAgentFeature>& mapping) -> bool { return mapping.first == accountIdMode; });
if (accountIdFeature == std::end(ACCOUNT_ID_MODE_MAPPING)) {
return {};
}
return accountIdFeature->second;
}

const char* EXEC_ENV_VAR = "AWS_EXECUTION_ENV";
const char* METADATA = "md";
const char* METADATA_DELIMINATOR = "/";
Expand Down Expand Up @@ -94,6 +116,10 @@ UserAgent::UserAgent(const ClientConfiguration& clientConfiguration,
#undef XSTR
#endif
{
const auto accountIdMode = BusinessMetricForAccountIdMode(clientConfiguration.accountIdEndpointMode);
if (accountIdMode.has_value()) {
m_features.emplace(accountIdMode.value());
}
}

Aws::String UserAgent::SerializeWithFeatures(const Aws::Set<UserAgentFeature>& features) const {
Expand Down
Loading
Loading