From 999e5fe5b7341386e54050380dabc270ba59ff55 Mon Sep 17 00:00:00 2001 From: Yenfry Herrera Feliz Date: Fri, 3 Jan 2025 09:17:57 -0800 Subject: [PATCH] fix: account id endpoint metric - Captures the AccountIdEndpointMode metric just if the parameter is defined in the ruleset. - Captures the account id endpoint metric whenever an account id endpoint was resolved by the endpoint middleware. --- src/EndpointV2/EndpointV2Middleware.php | 17 +++ src/MetricsBuilder.php | 43 +++++- src/UserAgentMiddleware.php | 21 --- tests/UserAgentMiddlewareTest.php | 173 +++++++++++++++++------- 4 files changed, 184 insertions(+), 70 deletions(-) diff --git a/src/EndpointV2/EndpointV2Middleware.php b/src/EndpointV2/EndpointV2Middleware.php index c271baae15..b3b6fa339a 100644 --- a/src/EndpointV2/EndpointV2Middleware.php +++ b/src/EndpointV2/EndpointV2Middleware.php @@ -99,10 +99,27 @@ public function __invoke(CommandInterface $command) $operation = $this->api->getOperation($command->getName()); $commandArgs = $command->toArray(); $providerArgs = $this->resolveArgs($commandArgs, $operation); + + // Resolved AccountId Metric if (!empty($providerArgs[self::ACCOUNT_ID_PARAM])) { $command->getMetricsBuilder()->append(MetricsBuilder::RESOLVED_ACCOUNT_ID); } + // AccountIdMode Metric + if(!empty($providerArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM])) { + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'account_id_endpoint_mode', + $providerArgs[self::ACCOUNT_ID_ENDPOINT_MODE_PARAM] + ); + } + $endpoint = $this->endpointProvider->resolveEndpoint($providerArgs); + + // AccountId Endpoint Metric + $command->getMetricsBuilder()->identifyMetricByValueAndAppend( + 'account_id_endpoint', + $endpoint->getUrl() + ); + if (!empty($authSchemes = $endpoint->getProperty('authSchemes'))) { $this->applyAuthScheme( $authSchemes, diff --git a/src/MetricsBuilder.php b/src/MetricsBuilder.php index 506b2c8020..9827f33fce 100644 --- a/src/MetricsBuilder.php +++ b/src/MetricsBuilder.php @@ -4,6 +4,7 @@ use Aws\Credentials\CredentialsInterface; use Aws\Credentials\CredentialSources; +use GuzzleHttp\Psr7\Uri; /** * A placeholder for gathering metrics in a request. @@ -136,7 +137,9 @@ public function identifyMetricByValueAndAppend( 'signature' => 'appendSignatureMetric', 'request_compression' => 'appendRequestCompressionMetric', 'request_checksum' => 'appendRequestChecksumMetric', - 'credentials' => 'appendCredentialsMetric' + 'credentials' => 'appendCredentialsMetric', + 'account_id_endpoint_mode' => 'appendAccountIdEndpointMode', + 'account_id_endpoint' => 'appendAccountIdEndpoint', ]; $fn = $appendMetricFns[$featureGroup]; @@ -244,6 +247,44 @@ private function appendCredentialsMetric( } } + /** + * Appends the account_id_endpoint_mode metrics based on + * the value resolved. + * + * @param string $accountIdEndpointMode + * + * @return void + */ + private function appendAccountIdEndpointMode( + string $accountIdEndpointMode + ): void + { + if (empty($accountIdEndpointMode)) { + return; + } + + if ($accountIdEndpointMode === 'preferred') { + $this->append(MetricsBuilder::ACCOUNT_ID_MODE_PREFERRED); + } elseif ($accountIdEndpointMode === 'disabled') { + $this->append(MetricsBuilder::ACCOUNT_ID_MODE_DISABLED); + } elseif ($accountIdEndpointMode === 'required') { + $this->append(MetricsBuilder::ACCOUNT_ID_MODE_REQUIRED); + } + } + + /** + * @param string $endpoint + * + * @return void + */ + private function appendAccountIdEndpoint(string $endpoint): void + { + static $pattern = "/(https|http):\\/\\/\\d{12}\\.ddb/"; + if (preg_match($pattern, $endpoint)) { + $this->append(MetricsBuilder::ACCOUNT_ID_ENDPOINT); + } + } + /** * Validates if a metric can be appended by ensuring the total size, * including the new metric and separator, does not exceed the limit. diff --git a/src/UserAgentMiddleware.php b/src/UserAgentMiddleware.php index e98b2a2cdc..b548785587 100644 --- a/src/UserAgentMiddleware.php +++ b/src/UserAgentMiddleware.php @@ -30,7 +30,6 @@ class UserAgentMiddleware static $metricsFnList = [ 'appendEndpointMetric', - 'appendAccountIdModeMetric', 'appendRetryConfigMetric', ]; @@ -281,26 +280,6 @@ private function appendEndpointMetric(): void } } - /** - * Appends the account id endpoint mode metric into the metrics builder, - * based on the account id endpoint mode provide as client argument. - */ - private function appendAccountIdModeMetric(): void - { - $accountIdMode = $this->args['account_id_endpoint_mode'] ?? null; - if ($accountIdMode === null) { - return; - } - - if ($accountIdMode === 'preferred') { - $this->metricsBuilder->append(MetricsBuilder::ACCOUNT_ID_MODE_PREFERRED); - } elseif ($accountIdMode === 'disabled') { - $this->metricsBuilder->append(MetricsBuilder::ACCOUNT_ID_MODE_DISABLED); - } elseif ($accountIdMode === 'required') { - $this->metricsBuilder->append(MetricsBuilder::ACCOUNT_ID_MODE_REQUIRED); - } - } - /** * Appends the retry mode metric into the metrics builder, * based on the resolved retry config mode. diff --git a/tests/UserAgentMiddlewareTest.php b/tests/UserAgentMiddlewareTest.php index ee33a5d20f..032bfe8166 100644 --- a/tests/UserAgentMiddlewareTest.php +++ b/tests/UserAgentMiddlewareTest.php @@ -13,6 +13,7 @@ use Aws\Crypto\MaterialsProviderV2; use Aws\DynamoDb\DynamoDbClient; use Aws\EndpointV2\EndpointDefinitionProvider; +use Aws\EndpointV2\EndpointProviderV2; use Aws\MetricsBuilder; use Aws\Result; use Aws\S3\Crypto\S3EncryptionClient; @@ -211,27 +212,6 @@ public function userAgentCasesDataProvider(): \Generator return [$args, 'm/' . MetricsBuilder::ENDPOINT_OVERRIDE]; }, - 'metricsWithAccountIdModePreferred' => function (): array { - $args = [ - 'account_id_endpoint_mode' => 'preferred' - ]; - - return [$args, 'm/' . MetricsBuilder::ACCOUNT_ID_MODE_PREFERRED]; - }, - 'metricsWithAccountIdModeRequired' => function (): array { - $args = [ - 'account_id_endpoint_mode' => 'required' - ]; - - return [$args, 'm/' . MetricsBuilder::ACCOUNT_ID_MODE_REQUIRED]; - }, - 'metricsWithAccountIdModeDisabled' => function (): array { - $args = [ - 'account_id_endpoint_mode' => 'disabled' - ]; - - return [$args, 'm/' . MetricsBuilder::ACCOUNT_ID_MODE_DISABLED]; - }, 'metricsWithRetryConfigArrayStandardMode' => function (): array { $args = [ 'retries' => [ @@ -658,46 +638,143 @@ public function testUserAgentCaptureGzipRequestCompressionMetric() * @return void */ public function testUserAgentCaptureResolvedAccountIdMetric() + { + $dynamoDbClient = $this->getTestDynamoDBClient( + [ + 'credentials' => new Credentials( + 'foo', + 'foo', + 'foo', + null, + '123456789012' + ), + 'http_handler' => function ( + RequestInterface $request + ) { + $metrics = $this->getMetricsAsArray($request); + + $this->assertTrue( + in_array(MetricsBuilder::RESOLVED_ACCOUNT_ID, $metrics) + ); + + return new Response( + 200, + [], + '{}' + ); + } + ] + ); + $dynamoDbClient->listTables(); + } + + /** + * Tests user agent captures the accountIdEndpointMode metric. + * + * @return void + */ + public function testUserAgentCaptureResolvedAccountIdEndpointMode() { + $accountIdModesMetrics = [ + 'preferred' => MetricsBuilder::ACCOUNT_ID_MODE_PREFERRED, + 'required' => MetricsBuilder::ACCOUNT_ID_MODE_REQUIRED, + 'disabled' => MetricsBuilder::ACCOUNT_ID_MODE_DISABLED, + ]; + foreach ($accountIdModesMetrics as $config => $metric) { + $dynamoDbClient = $this->getTestDynamoDBClient( + [ + 'account_id_endpoint_mode' => $config, + 'credentials' => new Credentials( + 'foo', + 'foo', + 'foo', + null, + '123456789012' + ), + 'http_handler' => function ( + RequestInterface $request + ) use ($metric) { + $metrics = $this->getMetricsAsArray($request); + + $this->assertTrue( + in_array($metric, $metrics) + ); + + return new Response( + 200, + [], + '{}' + ); + } + ] + ); + $dynamoDbClient->listTables(); + } + } + + /** + * Tests user agent captures a resolved account id metric. + * + * @return void + */ + public function testUserAgentCaptureAccountIdEndpointMetric() + { + $dynamoDbClient = $this->getTestDynamoDBClient( + [ + 'credentials' => new Credentials( + 'foo', + 'foo', + 'foo', + null, + '123456789012' + ), + 'http_handler' => function ( + RequestInterface $request + ) { + $metrics = $this->getMetricsAsArray($request); + + $this->assertTrue( + in_array(MetricsBuilder::ACCOUNT_ID_ENDPOINT, $metrics) + ); + + return new Response( + 200, + [], + '{}' + ); + } + ] + ); + $dynamoDbClient->listTables(); + } + + /** + * Returns a test dynamodb client, + * where rules for resolving account endpoints + * are present. + * + * @param array $args + * + * @return DynamoDbClient + */ + private function getTestDynamoDBClient( + array $args + ): DynamoDbClient { try { $ruleSet = $this->getDynamoDBTestRuleSet(); } catch (\Exception $e) { $this->fail($e->getMessage()); } - - $dynamoDbClient = new DynamoDbClient([ + return new DynamoDbClient([ 'api_provider' => ApiProvider::filesystem( __DIR__ . '/fixtures/aws_client_test' ), - 'endpoint_provider' => new \Aws\EndpointV2\EndpointProviderV2( + 'endpoint_provider' => new EndpointProviderV2( $ruleSet, EndpointDefinitionProvider::getPartitions() ), 'region' => 'us-east-2', - 'credentials' => new Credentials( - 'foo', - 'foo', - 'foo', - null, - '123456789012' - ), - 'http_handler' => function ( - RequestInterface $request - ) { - $metrics = $this->getMetricsAsArray($request); - - $this->assertTrue( - in_array(MetricsBuilder::RESOLVED_ACCOUNT_ID, $metrics) - ); - - return new Response( - 200, - [], - '{}' - ); - } - ]); - $dynamoDbClient->listTables(); + ] + $args); } /**