Skip to content

Commit

Permalink
Move botocore version validation into module_utils.botocore for futur…
Browse files Browse the repository at this point in the history
…e reuse (ansible-collections#1227)

Move botocore version validation into module_utils.botocore for future reuse

Depends-On: ansible-collections#1246
SUMMARY
In preparation for ansible-collections#1225 move the SDK version validation pieces over into module_utils.botocore
ISSUE TYPE

Feature Pull Request

COMPONENT NAME
plugins/module_utils/botocore.py
plugins/module_utils/core.py
plugins/module_utils/exceptions.py
plugins/module_utils/modules.py
ADDITIONAL INFORMATION

Reviewed-by: Alina Buzachis <None>
Reviewed-by: Mark Chappell <None>
  • Loading branch information
tremble authored Nov 5, 2022
1 parent 8ff6340 commit c4be395
Show file tree
Hide file tree
Showing 4 changed files with 328 additions and 33 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/1227-refacter-sdk-versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- module_utils - refacter botocore version validation into module_utils.botocore for future reuse (https://github.com/ansible-collections/amazon.aws/pull/1227).
68 changes: 66 additions & 2 deletions plugins/module_utils/botocore.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@
from ansible.module_utils.six import binary_type
from ansible.module_utils.six import text_type

from .exceptions import AnsibleBotocoreError
from .retries import AWSRetry
from .version import LooseVersion

MINIMUM_BOTOCORE_VERSION = '1.21.0'
MINIMUM_BOTO3_VERSION = '1.18.0'


def boto3_conn(module, conn_type=None, resource=None, region=None, endpoint=None, **params):
Expand Down Expand Up @@ -245,8 +250,7 @@ def gather_sdk_versions():
"""
if not HAS_BOTO3:
return {}
import boto3
import botocore

return dict(boto3_version=boto3.__version__,
botocore_version=botocore.__version__)

Expand Down Expand Up @@ -355,3 +359,63 @@ def enable_placebo(session):
os.rmdir(os.environ["_ANSIBLE_PLACEBO_REPLAY"])
pill = placebo.attach(session, data_path="_tmp")
pill.playback()


def check_sdk_version_supported(botocore_version=None, boto3_version=None, warn=None):
""" Checks to see if the available boto3 / botocore versions are supported
args:
botocore_version: (str) overrides the minimum version of botocore supported by the collection
boto3_version: (str) overrides the minimum version of boto3 supported by the collection
warn: (Callable) invoked with a string message if boto3/botocore are less than the
supported versions
raises:
AnsibleBotocoreError - If botocore/boto3 is missing
returns
False if boto3 or botocore is less than the minimum supported versions
True if boto3 and botocore are greater than or equal the the minimum supported versions
"""

botocore_version = botocore_version or MINIMUM_BOTOCORE_VERSION
boto3_version = boto3_version or MINIMUM_BOTO3_VERSION

if not HAS_BOTO3:
raise AnsibleBotocoreError(message=missing_required_lib('botocore and boto3'))

supported = True

if not botocore_at_least(botocore_version):
supported = False
if warn:
warn('botocore < {0} is not supported or tested. Some features may not work.'.format(MINIMUM_BOTOCORE_VERSION))
if not boto3_at_least(boto3_version):
supported = False
if warn:
warn('boto3 < {0} is not supported or tested. Some features may not work.'.format(MINIMUM_BOTO3_VERSION))

return supported


def boto3_at_least(desired):
"""Check if the available boto3 version is greater than or equal to a desired version.
Usage:
if module.params.get('assign_ipv6_address') and not module.boto3_at_least('1.4.4'):
# conditionally fail on old boto3 versions if a specific feature is not supported
module.fail_json(msg="Boto3 can't deal with EC2 IPv6 addresses before version 1.4.4.")
"""
existing = gather_sdk_versions()
return LooseVersion(existing['boto3_version']) >= LooseVersion(desired)


def botocore_at_least(desired):
"""Check if the available botocore version is greater than or equal to a desired version.
Usage:
if not module.botocore_at_least('1.2.3'):
module.fail_json(msg='The Serverless Elastic Load Compute Service is not in botocore before v1.2.3')
if not module.botocore_at_least('1.5.3'):
module.warn('Botocore did not include waiters for Service X before 1.5.3. '
'To wait until Service X resources are fully available, update botocore.')
"""
existing = gather_sdk_versions()
return LooseVersion(existing['botocore_version']) >= LooseVersion(desired)
41 changes: 10 additions & 31 deletions plugins/module_utils/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,15 @@
from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
from ansible.module_utils._text import to_native

from .botocore import HAS_BOTO3
from .botocore import boto3_conn
from .botocore import boto3_at_least
from .botocore import botocore_at_least
from .botocore import check_sdk_version_supported
from .botocore import get_aws_connection_info
from .botocore import get_aws_region
from .botocore import gather_sdk_versions
from .exceptions import AnsibleBotocoreError
from .retries import RetryingBotoClientWrapper
from .version import LooseVersion

# Currently only AnsibleAWSModule. However we have a lot of Copy and Paste code
# for Inventory and Lookup modules which we should refactor
Expand Down Expand Up @@ -121,15 +123,10 @@ def __init__(self, **kwargs):
self._module = AnsibleAWSModule.default_settings["module_class"](**kwargs)

if local_settings["check_boto3"]:
if not HAS_BOTO3:
self._module.fail_json(
msg=missing_required_lib('botocore and boto3'))
if not self.botocore_at_least('1.21.0'):
self.warn('botocore < 1.21.0 is not supported or tested.'
' Some features may not work.')
if not self.boto3_at_least("1.18.0"):
self.warn('boto3 < 1.18.0 is not supported or tested.'
' Some features may not work.')
try:
check_sdk_version_supported(warn=self.warn)
except AnsibleBotocoreError as e:
self._module.fail_json(to_native(e))

deprecated_vars = {'EC2_REGION', 'EC2_SECURITY_TOKEN', 'EC2_SECRET_KEY', 'EC2_ACCESS_KEY',
'EC2_URL', 'S3_URL'}
Expand Down Expand Up @@ -291,15 +288,7 @@ def require_boto3_at_least(self, desired, **kwargs):
)

def boto3_at_least(self, desired):
"""Check if the available boto3 version is greater than or equal to a desired version.
Usage:
if module.params.get('assign_ipv6_address') and not module.boto3_at_least('1.4.4'):
# conditionally fail on old boto3 versions if a specific feature is not supported
module.fail_json(msg="Boto3 can't deal with EC2 IPv6 addresses before version 1.4.4.")
"""
existing = self._gather_versions()
return LooseVersion(existing['boto3_version']) >= LooseVersion(desired)
return boto3_at_least(desired)

def require_botocore_at_least(self, desired, **kwargs):
"""Check if the available botocore version is greater than or equal to a desired version.
Expand All @@ -321,17 +310,7 @@ def require_botocore_at_least(self, desired, **kwargs):
)

def botocore_at_least(self, desired):
"""Check if the available botocore version is greater than or equal to a desired version.
Usage:
if not module.botocore_at_least('1.2.3'):
module.fail_json(msg='The Serverless Elastic Load Compute Service is not in botocore before v1.2.3')
if not module.botocore_at_least('1.5.3'):
module.warn('Botocore did not include waiters for Service X before 1.5.3. '
'To wait until Service X resources are fully available, update botocore.')
"""
existing = self._gather_versions()
return LooseVersion(existing['botocore_version']) >= LooseVersion(desired)
return botocore_at_least(desired)


def _aws_common_argument_spec():
Expand Down
Loading

0 comments on commit c4be395

Please sign in to comment.