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

feat(parameters): migrate AppConfig to new APIs due to API deprecation #1553

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
43 changes: 24 additions & 19 deletions aws_lambda_powertools/utilities/parameters/appconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@

import os
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
from uuid import uuid4

import boto3
from botocore.config import Config

if TYPE_CHECKING:
from mypy_boto3_appconfig import AppConfigClient
from mypy_boto3_appconfigdata import AppConfigDataClient

from ...shared import constants
from ...shared.functions import resolve_env_var_choice
from .base import DEFAULT_MAX_AGE_SECS, DEFAULT_PROVIDERS, BaseProvider

CLIENT_ID = str(uuid4())


class AppConfigProvider(BaseProvider):
"""
Expand All @@ -34,8 +31,8 @@ class AppConfigProvider(BaseProvider):
Botocore configuration to pass during client initialization
boto3_session : boto3.session.Session, optional
Boto3 session to create a boto3_client from
boto3_client: AppConfigClient, optional
Boto3 AppConfig Client to use, boto3_session will be ignored if both are provided
boto3_client: AppConfigDataClient, optional
Boto3 AppConfigData Client to use, boto3_session will be ignored if both are provided

Example
-------
Expand Down Expand Up @@ -73,16 +70,16 @@ def __init__(
application: Optional[str] = None,
config: Optional[Config] = None,
boto3_session: Optional[boto3.session.Session] = None,
boto3_client: Optional["AppConfigClient"] = None,
boto3_client: Optional["AppConfigDataClient"] = None,
):
"""
Initialize the App Config client
"""

super().__init__()

self.client: "AppConfigClient" = self._build_boto3_client(
service_name="appconfig", client=boto3_client, session=boto3_session, config=config
self.client: "AppConfigDataClient" = self._build_boto3_client(
service_name="appconfigdata", client=boto3_client, session=boto3_session, config=config
)

self.application = resolve_env_var_choice(
Expand All @@ -91,6 +88,9 @@ def __init__(
self.environment = environment
self.current_version = ""

self.next_call = ""
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved
self.last_returned_value = ""

def _get(self, name: str, **sdk_options) -> str:
"""
Retrieve a parameter value from AWS App config.
Expand All @@ -100,16 +100,23 @@ def _get(self, name: str, **sdk_options) -> str:
name: str
Name of the configuration
sdk_options: dict, optional
Dictionary of options that will be passed to the client's get_configuration API call
Dictionary of options that will be passed to the client's start_configuration_session API call
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved
"""
if not self.next_call:
sdk_options["ConfigurationProfileIdentifier"] = name
sdk_options["ApplicationIdentifier"] = self.application
sdk_options["EnvironmentIdentifier"] = self.environment
response_configuration = self.client.start_configuration_session(**sdk_options)
self.next_call = response_configuration["InitialConfigurationToken"]

sdk_options["Configuration"] = name
sdk_options["Application"] = self.application
sdk_options["Environment"] = self.environment
sdk_options["ClientId"] = CLIENT_ID
response = self.client.get_latest_configuration(ConfigurationToken=self.next_call)
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved
return_value = response["Configuration"].read()
self.next_call = response["NextPollConfigurationToken"]

response = self.client.get_configuration(**sdk_options)
return response["Content"].read() # read() of botocore.response.StreamingBody
if return_value:
self.last_returned_value = return_value

return self.last_returned_value

def _get_multiple(self, path: str, **sdk_options) -> Dict[str, str]:
"""
Expand Down Expand Up @@ -145,7 +152,7 @@ def get_app_config(
max_age: int
Maximum age of the cached value
sdk_options: dict, optional
Dictionary of options that will be passed to the boto client get_configuration API call
Dictionary of options that will be passed to the boto client start_configuration_session API call
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved

Raises
------
Expand Down Expand Up @@ -180,8 +187,6 @@ def get_app_config(
if "appconfig" not in DEFAULT_PROVIDERS:
DEFAULT_PROVIDERS["appconfig"] = AppConfigProvider(environment=environment, application=application)

sdk_options["ClientId"] = CLIENT_ID

return DEFAULT_PROVIDERS["appconfig"].get(
name, max_age=max_age, transform=transform, force_fetch=force_fetch, **sdk_options
)
4 changes: 2 additions & 2 deletions aws_lambda_powertools/utilities/parameters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .exceptions import GetParameterError, TransformParameterError

if TYPE_CHECKING:
from mypy_boto3_appconfig import AppConfigClient
from mypy_boto3_appconfigdata import AppConfigDataClient
from mypy_boto3_dynamodb import DynamoDBServiceResource
from mypy_boto3_secretsmanager import SecretsManagerClient
from mypy_boto3_ssm import SSMClient
Expand All @@ -28,7 +28,7 @@
TRANSFORM_METHOD_JSON = "json"
TRANSFORM_METHOD_BINARY = "binary"
SUPPORTED_TRANSFORM_METHODS = [TRANSFORM_METHOD_JSON, TRANSFORM_METHOD_BINARY]
ParameterClients = Union["AppConfigClient", "SecretsManagerClient", "SSMClient"]
ParameterClients = Union["AppConfigDataClient", "SecretsManagerClient", "SSMClient"]


class BaseProvider(ABC):
Expand Down
7 changes: 7 additions & 0 deletions docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Changes at a glance:
* The API for **event handler's `Response`** has minor changes to support multi value headers and cookies.
* The **legacy SQS batch processor** was removed.
* The **Idempotency key** format changed slightly, invalidating all the existing cached results.
* The **Feature Flags and AppConfig Parameter utility** API calls have changed and you must add new IAM permissions to Lambda.
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved

???+ important
Powertools for Python v2 drops suport for Python 3.6, following the Python 3.6 End-Of-Life (EOL) reached on December 23, 2021.
Expand Down Expand Up @@ -154,3 +155,9 @@ Prior to this change, the Idempotency key was generated using only the caller fu
After this change, the key is generated using the `module name` + `qualified function name` + `idempotency key` (e.g: `app.classExample.function#app.handler#282e83393862a613b612c00283fef4c8`).

Using qualified names prevents distinct functions with the same name to contend for the same Idempotency key.

## Feature Flags and AppConfig Parameter utility
heitorlessa marked this conversation as resolved.
Show resolved Hide resolved

The current API is [deprecated](https://docs.aws.amazon.com/appconfig/2019-10-09/APIReference/API_GetConfiguration.html) for new accounts and we had to change this.

No changes are required to your code, but you must add `appconfig:GetLatestConfiguration` and `appconfig:StartConfigurationSession` IAM permissions for this to work in your Lambdas.
leandrodamascena marked this conversation as resolved.
Show resolved Hide resolved
Loading