-
Notifications
You must be signed in to change notification settings - Fork 429
feat(parameters): accept boto3_client to support private endpoints and ease testing #1096
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
Changes from 3 commits
ce851e9
b9b6753
159ca22
d33201e
2fbdca3
ac5554f
cd426fe
cd71ee0
ccc378b
2a77841
9b99f0b
d2c8f30
d854f1c
63bdde6
3528b8e
579f8e1
a8350ae
cec2f33
19ec9ae
58e2d5e
98dc539
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,7 +30,9 @@ class AppConfigProvider(BaseProvider): | |
config: botocore.config.Config, optional | ||
Botocore configuration to pass during client initialization | ||
boto3_session : boto3.session.Session, optional | ||
Boto3 session to use for AWS API communication | ||
Boto3 session to use for AWS API communication, will not be used if boto3_client is not None | ||
boto3_client: boto3.client, optional | ||
Boto3 Client to use for AWS API communication, will be used instead of boto3_session if both provided | ||
|
||
Example | ||
------- | ||
|
@@ -68,14 +70,19 @@ def __init__( | |
application: Optional[str] = None, | ||
config: Optional[Config] = None, | ||
boto3_session: Optional[boto3.session.Session] = None, | ||
boto3_client: Optional[boto3.client] = None, | ||
): | ||
""" | ||
Initialize the App Config client | ||
""" | ||
|
||
config = config or Config() | ||
session = boto3_session or boto3.session.Session() | ||
self.client = session.client("appconfig", config=config) | ||
if boto3_client is not None: | ||
self.client = boto3_client | ||
else: | ||
session = boto3_session or boto3.session.Session() | ||
self.client = session.client("appconfig", config=config) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we turn this into a builder static method in the parent class? Return type could be Any as we will be able to cast the correct one for each client built w/ mypy_boto3. This will prevent future an accidental logic discrepancy between them and localize change. It could accept the Let me know if it doesn't make sense There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i didnt add it to the dymamo class becuase we dont use a client there, not usre you can create a table from a client class. |
||
self.application = resolve_env_var_choice( | ||
choice=application, env=os.getenv(constants.SERVICE_NAME_ENV, "service_undefined") | ||
) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -24,14 +24,14 @@ This utility requires additional permissions to work as expected. | |||||||||||||||||||||||||||||||||||||||||||
???+ note | ||||||||||||||||||||||||||||||||||||||||||||
Different parameter providers require different permissions. | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Provider | Function/Method | IAM Permission | ||||||||||||||||||||||||||||||||||||||||||||
------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||
SSM Parameter Store | `get_parameter`, `SSMProvider.get` | `ssm:GetParameter` | ||||||||||||||||||||||||||||||||||||||||||||
SSM Parameter Store | `get_parameters`, `SSMProvider.get_multiple` | `ssm:GetParametersByPath` | ||||||||||||||||||||||||||||||||||||||||||||
Secrets Manager | `get_secret`, `SecretsManager.get` | `secretsmanager:GetSecretValue` | ||||||||||||||||||||||||||||||||||||||||||||
DynamoDB | `DynamoDBProvider.get` | `dynamodb:GetItem` | ||||||||||||||||||||||||||||||||||||||||||||
DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb:Query` | ||||||||||||||||||||||||||||||||||||||||||||
App Config | `AppConfigProvider.get_app_config`, `get_app_config` | `appconfig:GetConfiguration` | ||||||||||||||||||||||||||||||||||||||||||||
| Provider | Function/Method | IAM Permission | | ||||||||||||||||||||||||||||||||||||||||||||
heitorlessa marked this conversation as resolved.
Show resolved
Hide resolved
heitorlessa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||
| ------------------- | ---------------------------------------------------- | ------------------------------- | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameter`, `SSMProvider.get` | `ssm:GetParameter` | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameters`, `SSMProvider.get_multiple` | `ssm:GetParametersByPath` | | ||||||||||||||||||||||||||||||||||||||||||||
| Secrets Manager | `get_secret`, `SecretsManager.get` | `secretsmanager:GetSecretValue` | | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get` | `dynamodb:GetItem` | | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb:Query` | | ||||||||||||||||||||||||||||||||||||||||||||
| App Config | `AppConfigProvider.get_app_config`, `get_app_config` | `appconfig:GetConfiguration` | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
### Fetching parameters | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
@@ -147,10 +147,10 @@ def handler(event, context): | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
The AWS Systems Manager Parameter Store provider supports two additional arguments for the `get()` and `get_multiple()` methods: | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| Parameter | Default | Description | | ||||||||||||||||||||||||||||||||||||||||||||
|---------------|---------|-------------| | ||||||||||||||||||||||||||||||||||||||||||||
| **decrypt** | `False` | Will automatically decrypt the parameter. | ||||||||||||||||||||||||||||||||||||||||||||
| **recursive** | `True` | For `get_multiple()` only, will fetch all parameter values recursively based on a path prefix. | ||||||||||||||||||||||||||||||||||||||||||||
| Parameter | Default | Description | | ||||||||||||||||||||||||||||||||||||||||||||
| ------------- | ------- | ---------------------------------------------------------------------------------------------- | | ||||||||||||||||||||||||||||||||||||||||||||
| **decrypt** | `False` | Will automatically decrypt the parameter. | | ||||||||||||||||||||||||||||||||||||||||||||
| **recursive** | `True` | For `get_multiple()` only, will fetch all parameter values recursively based on a path prefix. | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
```python hl_lines="6 8" title="Example with get() and get_multiple()" | ||||||||||||||||||||||||||||||||||||||||||||
from aws_lambda_powertools.utilities import parameters | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -189,9 +189,9 @@ For single parameters, you must use `id` as the [partition key](https://docs.aws | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
DynamoDB table with `id` partition key and `value` as attribute | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| id | value | | ||||||||||||||||||||||||||||||||||||||||||||
|--------------|----------| | ||||||||||||||||||||||||||||||||||||||||||||
| my-parameter | my-value | | ||||||||||||||||||||||||||||||||||||||||||||
| id | value | | ||||||||||||||||||||||||||||||||||||||||||||
| ------------ | -------- | | ||||||||||||||||||||||||||||||||||||||||||||
| my-parameter | my-value | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
With this table, `dynamodb_provider.get("my-param")` will return `my-value`. | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
@@ -223,11 +223,11 @@ You can retrieve multiple parameters sharing the same `id` by having a sort key | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
DynamoDB table with `id` primary key, `sk` as sort key` and `value` as attribute | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| id | sk | value | | ||||||||||||||||||||||||||||||||||||||||||||
|-------------|---------|------------| | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-a | my-value-a | | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-b | my-value-b | | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-c | my-value-c | | ||||||||||||||||||||||||||||||||||||||||||||
| id | sk | value | | ||||||||||||||||||||||||||||||||||||||||||||
| ----------- | ------- | ---------- | | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-a | my-value-a | | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-b | my-value-b | | ||||||||||||||||||||||||||||||||||||||||||||
| my-hash-key | param-c | my-value-c | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
With this table, `dynamodb_provider.get_multiple("my-hash-key")` will return a dictionary response in the shape of `sk:value`. | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
@@ -261,12 +261,12 @@ With this table, `dynamodb_provider.get_multiple("my-hash-key")` will return a d | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
DynamoDB provider can be customized at initialization to match your table structure: | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| Parameter | Mandatory | Default | Description | | ||||||||||||||||||||||||||||||||||||||||||||
|----------------|-----------|---------|-------------| | ||||||||||||||||||||||||||||||||||||||||||||
| **table_name** | **Yes** | *(N/A)* | Name of the DynamoDB table containing the parameter values. | ||||||||||||||||||||||||||||||||||||||||||||
| **key_attr** | No | `id` | Hash key for the DynamoDB table. | ||||||||||||||||||||||||||||||||||||||||||||
| **sort_attr** | No | `sk` | Range key for the DynamoDB table. You don't need to set this if you don't use the `get_multiple()` method. | ||||||||||||||||||||||||||||||||||||||||||||
| **value_attr** | No | `value` | Name of the attribute containing the parameter value. | ||||||||||||||||||||||||||||||||||||||||||||
| Parameter | Mandatory | Default | Description | | ||||||||||||||||||||||||||||||||||||||||||||
| -------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------- | | ||||||||||||||||||||||||||||||||||||||||||||
| **table_name** | **Yes** | *(N/A)* | Name of the DynamoDB table containing the parameter values. | | ||||||||||||||||||||||||||||||||||||||||||||
| **key_attr** | No | `id` | Hash key for the DynamoDB table. | | ||||||||||||||||||||||||||||||||||||||||||||
| **sort_attr** | No | `sk` | Range key for the DynamoDB table. You don't need to set this if you don't use the `get_multiple()` method. | | ||||||||||||||||||||||||||||||||||||||||||||
| **value_attr** | No | `value` | Name of the attribute containing the parameter value. | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
```python hl_lines="3-8" title="Customizing DynamoDBProvider to suit your table design" | ||||||||||||||||||||||||||||||||||||||||||||
from aws_lambda_powertools.utilities import parameters | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -467,22 +467,22 @@ def handler(event, context): | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Here is the mapping between this utility's functions and methods and the underlying SDK: | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
| Provider | Function/Method | Client name | Function name | | ||||||||||||||||||||||||||||||||||||||||||||
|---------------------|---------------------------------|------------------|----------------| | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | | ||||||||||||||||||||||||||||||||||||||||||||
| Provider | Function/Method | Client name | Function name | | ||||||||||||||||||||||||||||||||||||||||||||
| ------------------- | ------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameter` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `get_parameters` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `SSMProvider.get` | `ssm` | [get_parameter](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameter) | | ||||||||||||||||||||||||||||||||||||||||||||
| SSM Parameter Store | `SSMProvider.get_multiple` | `ssm` | [get_parameters_by_path](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ssm.html#SSM.Client.get_parameters_by_path) | | ||||||||||||||||||||||||||||||||||||||||||||
| Secrets Manager | `get_secret` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) | | ||||||||||||||||||||||||||||||||||||||||||||
| Secrets Manager | `SecretsManager.get` | `secretsmanager` | [get_secret_value](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html#SecretsManager.Client.get_secret_value) | | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) | ||||||||||||||||||||||||||||||||||||||||||||
| App Config | `get_app_config` | `appconfig` | [get_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfig.html#AppConfig.Client.get_configuration) | | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [get_item](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.get_item) | | ||||||||||||||||||||||||||||||||||||||||||||
| DynamoDB | `DynamoDBProvider.get_multiple` | `dynamodb` | ([Table resource](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#table)) | [query](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.query) | | ||||||||||||||||||||||||||||||||||||||||||||
| App Config | `get_app_config` | `appconfig` | [get_configuration](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/appconfig.html#AppConfig.Client.get_configuration) | | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
### Customizing boto configuration | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
The **`config`** and **`boto3_session`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) or a custom [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html) when constructing any of the built-in provider classes. | ||||||||||||||||||||||||||||||||||||||||||||
The **`config`** and **`boto3_session`** and **`boto3_client`** parameters enable you to pass in a custom [botocore config object](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) or a custom [boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html) or a custom [boto3 client](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/boto3.html) when constructing any of the built-in provider classes. | ||||||||||||||||||||||||||||||||||||||||||||
heitorlessa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
???+ tip | ||||||||||||||||||||||||||||||||||||||||||||
You can use a custom session for retrieving parameters cross-account/region and for snapshot testing. | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -516,6 +516,22 @@ The **`config`** and **`boto3_session`** parameters enable you to pass in a cust | |||||||||||||||||||||||||||||||||||||||||||
... | ||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
=== "Custom client" | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
```python hl_lines="2 4 5" | ||||||||||||||||||||||||||||||||||||||||||||
from aws_lambda_powertools.utilities import parameters | ||||||||||||||||||||||||||||||||||||||||||||
import boto3 | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
boto3_client= boto3.client("ssm") | ||||||||||||||||||||||||||||||||||||||||||||
ssm_provider = parameters.SSMProvider(boto3_client=boto3_client) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def handler(event, context): | ||||||||||||||||||||||||||||||||||||||||||||
# Retrieve a single parameter | ||||||||||||||||||||||||||||||||||||||||||||
value = ssm_provider.get("/my/parameter") | ||||||||||||||||||||||||||||||||||||||||||||
... | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+562
to
+571
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would update the example to still use boto session to create the client (see boto3 Sessions, and Why You Should Use Them ). And showcase what you can do when you create your own client, like customerize the endpoint url as per the original issue.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
## Testing your code | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
For unit testing your applications, you can mock the calls to the parameters utility to avoid calling AWS APIs. This | ||||||||||||||||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.