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 13 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."
}
]
6 changes: 5 additions & 1 deletion src/AwsClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,11 @@ private function setClientBuiltIns($args)
$config = $this->getConfig();
$service = $args['service'];

$builtIns['SDK::Endpoint'] = isset($args['endpoint']) ? $args['endpoint'] : null;
$builtIns['SDK::Endpoint'] = isset($config['endpoint_url'])
? $config['endpoint_url']
: (isset($args['endpoint'])
? $args['endpoint']
: null);
$builtIns['AWS::Region'] = $this->getRegion();
$builtIns['AWS::UseFIPS'] = $config['use_fips_endpoint']->isUseFipsEndpoint();
$builtIns['AWS::UseDualStack'] = $config['use_dual_stack_endpoint']->isUseDualstackEndpoint();
Expand Down
72 changes: 72 additions & 0 deletions src/ClientResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,20 @@ class ClientResolver
'default' => false,
'fn' => [__CLASS__, '_apply_suppress_php_deprecation_warning']
],
'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_url' => [
'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). This functions in an identical manner to and will take precedence over the `endpoint` configuration option and can also be resolved from environment variables and the shared config file.',
'fn' => [__CLASS__, '_apply_endpoint_url'],
'default' => [__CLASS__, '_default_endpoint_url'],
]
];

/**
Expand Down Expand Up @@ -1137,6 +1151,64 @@ 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 _apply_endpoint_url($value, array &$args)
{
if (empty($value)) {
return;
}

$args['config']['endpoint_url'] = $value;
}

public static function _default_endpoint_url(array &$args)
{
if ($args['config']['ignore_configured_endpoint_urls']
|| !self::isValidService($args['service'])
) {
return '';
}

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

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

return $value;
}

public static function _missing_region(array $args)
{
$service = isset($args['service']) ? $args['service'] : '';
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 = []
)
{
$options = isset($config['config_resolver_options'])
? $config['config_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,
$options
);
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 = []
){
$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(
$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
);
}
}
45 changes: 45 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,51 @@ function boolean_value($input)
return null;
}

/**
* Checks if an input is a valid epoch time
*
* @param $filename
* @param $filename
* @return array
*/
function parse_ini_section_with_subsections($filename, $section_name) {
$config = [];
$ini_content = file_get_contents($filename);
$lines = explode("\n", $ini_content);

$section_start = false;
$current_subsection = '';

foreach ($lines as $line) {
$line = trim($line);

if (empty($line) || strpos($line, ';') === 0 || strpos($line, '#') === 0) {
continue; // Ignore empty lines and comments
}

if (strpos($line, '[') === 0) {
if ($section_start) {
break;
}
$current_subsection = '';
$section_start = (trim($line, '[]') === $section_name);
} elseif ($section_start) {
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] = [];
}
}
}
return $config;
}

/**
* Checks if an input is a valid epoch time
*
Expand Down
18 changes: 17 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 Expand Up @@ -511,6 +512,21 @@ public function testGetClientBuiltins()
);
}

public function testPrefersEndpointUrlToEndpoint()
{
$client = new StsClient([
'region' => 'us-west-2',
'version' => 'latest',
'endpoint' => 'https://foo-bar.com',
'endpoint_url' => 'https://exmaple.com'
]);
$builtIns = $client->getClientBuiltIns();
$this->assertEquals(
$builtIns['SDK::Endpoint'],
'https://exmaple.com'
);
}

public function testGetEndpointProviderArgs()
{
$client = new StsClient([
Expand Down
Loading