Skip to content
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

feature: add support for per-service endpoint url configuration #2737

Merged
merged 31 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
efb74ce
add support for per-service endpoint url configuration
Jul 25, 2023
681f83b
update heredoc
Jul 25, 2023
371bca4
unset env vars
Jul 25, 2023
8c15d73
add ignore configured urls to default config
Jul 25, 2023
8aa98e0
add test for ignore_configure_endpoint_urls
Jul 26, 2023
44fb436
update docs
Aug 8, 2023
5a0688f
refactor configresolver params
Aug 8, 2023
d8fde5f
make options optional
Aug 8, 2023
c850943
config resolver test changes
Aug 8, 2023
2ea8a52
refactor function to generic subsection parser
Aug 10, 2023
cd83c2b
update config resolver test
Aug 10, 2023
114c3d1
undo key-value alignment
Aug 10, 2023
f49b2e5
add annotation to config resolver
Aug 10, 2023
23dfa95
Merge branch 'master' into endpoint-url-config
stobrien89 Aug 29, 2023
a98619b
update tests, address feedback
Aug 30, 2023
7dc33d7
update ignore endpoint url config test
Aug 30, 2023
93a5eba
update service ini test
Aug 30, 2023
13e09a2
update subsection parser to stream
Aug 30, 2023
febc64d
update subsection parser to merge values if duplicated
Aug 31, 2023
9aaefff
update comments
Aug 31, 2023
c414902
refactor subsection parser
Aug 31, 2023
f1a2eba
add newline to changelog entry
Aug 31, 2023
7875dc0
add newline to configurationresolvertest
Aug 31, 2023
cd6e975
switch option to legacy endpoint option
Aug 31, 2023
e194339
ensure endpoint is not set in args if not provided
Aug 31, 2023
ae85893
updates based on feedback
Sep 1, 2023
f79f384
update closing brackets
Sep 1, 2023
2942964
remove explicit evaluation
Sep 1, 2023
178befd
undo builtin changes
Sep 1, 2023
a98ed65
undo builtin changes
Sep 1, 2023
9328d9e
update clientresolver docs
Sep 1, 2023
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
7 changes: 7 additions & 0 deletions .changes/nextrelease/endpoint-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "feature",
"category": "",
"description": "Adds support for service-specific endpoint url configuration."
}
]
62 changes: 62 additions & 0 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,19 @@ class ClientResolver
'doc' => 'Set to true to disable host prefix injection logic for services that use it. This disables the entire prefix injection, including the portions supplied by user-defined parameters. Setting this flag will have no effect on services that do not use host prefix injection.',
'default' => false,
],
'ignore_configured_endpoint_urls' => [
'type' => 'value',
'valid' => ['bool'],
'doc' => 'Set to true to disable endpoint urls configured using the `endpoint_url` configuration option.',
'fn' => [__CLASS__, '_apply_ignore_configured_endpoint_urls'],
'default' => [__CLASS__, '_default_ignore_configured_endpoint_urls'],
],
'endpoint' => [
'type' => 'value',
'valid' => ['string'],
'doc' => 'The full URI of the webservice. This is only required when connecting to a custom endpoint (e.g., a local version of S3).',
'fn' => [__CLASS__, '_apply_endpoint'],
'default' => [__CLASS__, '_default_endpoint']
],
'region' => [
'type' => 'value',
Expand Down Expand Up @@ -993,6 +1001,11 @@ public static function _apply_user_agent($inputUserAgent, array &$args, HandlerL

public static function _apply_endpoint($value, array &$args, HandlerList $list)
{
if (empty($value)) {
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
unset($args['endpoint']);
return;
}

$args['endpoint'] = $value;
}

Expand Down Expand Up @@ -1116,6 +1129,55 @@ public static function _default_signing_region(array &$args)
: $args['region'];
}

public static function _apply_ignore_configured_endpoint_urls($value, array &$args)
{
$args['config']['ignore_configured_endpoint_urls'] = $value;
}

public static function _default_ignore_configured_endpoint_urls(array &$args)
{
return ConfigurationResolver::resolve(
'ignore_configured_endpoint_urls',
false,
'bool',
$args
);
}

public static function _default_endpoint(array &$args)
{
if ($args['config']['ignore_configured_endpoint_urls']
|| !self::isValidService($args['service'])
SamRemis marked this conversation as resolved.
Show resolved Hide resolved
) {
return '';
}

$serviceIdentifier = \Aws\manifest($args['service'])['serviceIdentifier'];
$value = ConfigurationResolver::resolve(
'endpoint_url_' . $serviceIdentifier,
'',
'string',
$args + [
'ini_resolver_options' => [
'section' => 'services',
'subsection' => $serviceIdentifier,
'key' => 'endpoint_url'
]
]
);

if (empty($value)) {
$value = ConfigurationResolver::resolve(
'endpoint_url',
'',
'string',
$args
);
}

return $value;
}

public static function _apply_region($value, array &$args)
{
if (empty($value)) {
Expand Down
2 changes: 2 additions & 0 deletions src/CloudSearchDomain/CloudSearchDomainClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Aws\AwsClient;
use Aws\CommandInterface;
use Aws\HandlerList;
use GuzzleHttp\Psr7\Uri;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\Psr7;
Expand Down Expand Up @@ -35,6 +36,7 @@ public static function getArguments()
// (e.g. http://search-blah.{region}.cloudsearch.amazonaws.com)
return explode('.', new Uri($args['endpoint']))[1];
};
unset($args['endpoint']['default']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? This seems like an endpoint is always required, so it should never go to the default?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client resolver won't handle the 'required' property if there's a default


return $args;
}
Expand Down
82 changes: 76 additions & 6 deletions src/Configuration/ConfigurationResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ class ConfigurationResolver
* to retrieve value from the environment or ini file.
* @param mixed $defaultValue
* @param string $expectedType The expected type of the retrieved value.
* @param array $config
* @param array $additionalArgs
* @param array $config additional configuration options.
*
* @return mixed
*/
Expand All @@ -33,6 +32,10 @@ public static function resolve(
$config = []
)
{
$iniOptions = isset($config['ini_resolver_options'])
? $config['ini_resolver_options']
: [];

$envValue = self::env($key, $expectedType);
if (!is_null($envValue)) {
return $envValue;
Expand All @@ -41,7 +44,13 @@ public static function resolve(
if (!isset($config['use_aws_shared_config_files'])
|| $config['use_aws_shared_config_files'] != false
) {
$iniValue = self::ini($key, $expectedType);
$iniValue = self::ini(
$key,
$expectedType,
null,
null,
$iniOptions
);
if(!is_null($iniValue)) {
return $iniValue;
}
Expand Down Expand Up @@ -89,8 +98,13 @@ public static function env($key, $expectedType)
*
* @return null | mixed
*/
public static function ini($key, $expectedType, $profile = null, $filename = null)
{
public static function ini(
$key,
$expectedType,
$profile = null,
$filename = null,
$options = []
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
){
$filename = $filename ?: (self::getDefaultConfigFilename());
$profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');

Expand All @@ -100,6 +114,20 @@ public static function ini($key, $expectedType, $profile = null, $filename = nul
// Use INI_SCANNER_NORMAL instead of INI_SCANNER_TYPED for PHP 5.5 compatibility
//TODO change after deprecation
$data = @\Aws\parse_ini_file($filename, true, INI_SCANNER_NORMAL);

if (isset($options['section'])
&& isset($options['subsection'])
&& isset($options['key']))
{
return self::retrieveValueFromIniSubsection(
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
$data,
$profile,
$filename,
$expectedType,
$options
);
}

if ($data === false
|| !isset($data[$profile])
|| !isset($data[$profile][$key])
Expand Down Expand Up @@ -177,4 +205,46 @@ private static function convertType($value, $type)
}
return $value;
}
}

/**
* Normalizes string values pulled out of ini files and
* environment variables.
*
* @param array $data The data retrieved the ini file
* @param string $profile The specified ini profile
* @param string $filename The full path to the ini file
* @param array $options Additional arguments passed to the configuration resolver
*
* @return mixed
*/
private static function retrieveValueFromIniSubsection(
$data,
$profile,
$filename,
$expectedType,
$options
){
$section = $options['section'];
if ($data === false
|| !isset($data[$profile][$section])
|| !isset($data["{$section} {$data[$profile][$section]}"])
) {
return null;
}

$services_section = \Aws\parse_ini_section_with_subsections(
$filename,
"services {$data[$profile]['services']}"
);

if (!isset($services_section[$options['subsection']][$options['key']])
) {
return null;
}

return self::convertType(
$services_section[$options['subsection']][$options['key']],
$expectedType
);
}
}
61 changes: 61 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,67 @@ function boolean_value($input)
return null;
}

/**
* Parses ini sections with subsections (i.e. the service section)
*
* @param $filename
* @param $filename
* @return array
*/
function parse_ini_section_with_subsections($filename, $section_name) {
$config = [];
$stream = fopen($filename, 'r');

if (!$stream) {
return $config;
}

$current_subsection = '';
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved

while (!feof($stream)) {
$line = trim(fgets($stream));
SamRemis marked this conversation as resolved.
Show resolved Hide resolved

if (empty($line) || in_array($line[0], [';', '#'])) {
continue;
}

if (preg_match('/^\[.*\]$/', $line)
&& trim($line, '[]') === $section_name)
{
while (!feof($stream)) {
$line = trim(fgets($stream));

if (empty($line) || in_array($line[0], [';', '#'])) {
continue;
}

if (preg_match('/^\[.*\]$/', $line)
&& trim($line, '[]') === $section_name)
{
continue;
} elseif (strpos($line, '[') === 0) {
break;
}

if (strpos($line, ' = ') !== false) {
list($key, $value) = explode(' = ', $line, 2);
if (empty($current_subsection)) {
$config[$key] = $value;
} else {
$config[$current_subsection][$key] = $value;
}
} else {
$current_subsection = trim(str_replace('=', '', $line));
$config[$current_subsection] = [];
}
}
}
}

fclose($stream);
return $config;
}

/**
* Checks if an input is a valid epoch time
*
Expand Down
3 changes: 2 additions & 1 deletion tests/AwsClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@ public function testVerifyGetConfig()
'use_fips_endpoint' => new FipsConfiguration(false),
'use_dual_stack_endpoint' => new DualStackConfiguration(false, "foo"),
'disable_request_compression' => false,
'request_min_compression_size_bytes' => 10240
'request_min_compression_size_bytes' => 10240,
'ignore_configured_endpoint_urls' => false
],
$client->getConfig()
);
Expand Down
Loading