updated boto_lambda execution module with 'lambda environment variables'

This commit is contained in:
Winston Liu 2017-01-30 16:00:16 -08:00
parent 781c15de1c
commit dc8344f0c2
2 changed files with 317 additions and 220 deletions

View File

@ -73,7 +73,7 @@ Connection module for Amazon Lambda
''' '''
# keep lint from choking on _get_conn and _cache_id # keep lint from choking on _get_conn and _cache_id
#pylint: disable=E0602 # pylint: disable=E0602
# Import Python libs # Import Python libs
from __future__ import absolute_import from __future__ import absolute_import
@ -97,11 +97,12 @@ log = logging.getLogger(__name__)
# pylint: disable=import-error # pylint: disable=import-error
try: try:
#pylint: disable=unused-import # pylint: disable=unused-import
import boto import boto
import boto3 import boto3
#pylint: enable=unused-import # pylint: enable=unused-import
from botocore.exceptions import ClientError from botocore.exceptions import ClientError
from botocore import __version__ as found_botocore_version
logging.getLogger('boto').setLevel(logging.CRITICAL) logging.getLogger('boto').setLevel(logging.CRITICAL)
logging.getLogger('boto3').setLevel(logging.CRITICAL) logging.getLogger('boto3').setLevel(logging.CRITICAL)
HAS_BOTO = True HAS_BOTO = True
@ -117,9 +118,11 @@ def __virtual__():
''' '''
required_boto_version = '2.8.0' required_boto_version = '2.8.0'
required_boto3_version = '1.2.5' required_boto3_version = '1.2.5'
required_botocore_version = '1.5.2'
# the boto_lambda execution module relies on the connect_to_region() method # the boto_lambda execution module relies on the connect_to_region() method
# which was added in boto 2.8.0 # which was added in boto 2.8.0
# https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12 # https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
# botocore version >= 1.5.2 is required due to lambda environment variables
if not HAS_BOTO: if not HAS_BOTO:
return (False, 'The boto_lambda module could not be loaded: ' return (False, 'The boto_lambda module could not be loaded: '
'boto libraries not found') 'boto libraries not found')
@ -129,6 +132,9 @@ def __virtual__():
elif _LooseVersion(boto3.__version__) < _LooseVersion(required_boto3_version): elif _LooseVersion(boto3.__version__) < _LooseVersion(required_boto3_version):
return (False, 'The boto_lambda module could not be loaded: ' return (False, 'The boto_lambda module could not be loaded: '
'boto version {0} or later must be installed.'.format(required_boto3_version)) 'boto version {0} or later must be installed.'.format(required_boto3_version))
elif _LooseVersion(found_botocore_version) < _LooseVersion(required_botocore_version):
return (False, 'The boto_apigateway module could not be loaded: '
'botocore version {0} or later must be installed.'.format(required_botocore_version))
else: else:
return True return True
@ -140,8 +146,7 @@ def __init__(opts):
def _find_function(name, def _find_function(name,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given function name, find and return matching Lambda information. Given function name, find and return matching Lambda information.
''' '''
@ -155,7 +160,7 @@ def _find_function(name,
def function_exists(FunctionName, region=None, key=None, def function_exists(FunctionName, region=None, key=None,
keyid=None, profile=None): keyid=None, profile=None):
''' '''
Given a function name, check to see if the given function name exists. Given a function name, check to see if the given function name exists.
@ -172,7 +177,7 @@ def function_exists(FunctionName, region=None, key=None,
try: try:
func = _find_function(FunctionName, func = _find_function(FunctionName,
region=region, key=key, keyid=keyid, profile=profile) region=region, key=key, keyid=keyid, profile=profile)
return {'exists': bool(func)} return {'exists': bool(func)}
except ClientError as e: except ClientError as e:
return {'error': salt.utils.boto3.get_error(e)} return {'error': salt.utils.boto3.get_error(e)}
@ -201,10 +206,22 @@ def create_function(FunctionName, Runtime, Role, Handler, ZipFile=None,
S3Bucket=None, S3Key=None, S3ObjectVersion=None, S3Bucket=None, S3Key=None, S3ObjectVersion=None,
Description="", Timeout=3, MemorySize=128, Publish=False, Description="", Timeout=3, MemorySize=128, Publish=False,
WaitForRole=False, RoleRetries=5, WaitForRole=False, RoleRetries=5,
region=None, key=None, keyid=None, profile=None, VpcConfig=None): region=None, key=None, keyid=None, profile=None,
VpcConfig=None, Environment=None):
''' '''
Given a valid config, create a function. Given a valid config, create a function.
Environment
The parent object that contains your environment's configuration
settings. This is a dictionary of the form:
{
'Variables': {
'VariableName': 'VariableValue'
}
}
.. versionadded:: Nitrogen
Returns {created: true} if the function was created and returns Returns {created: true} if the function was created and returns
{created: False} if the function was not created. {created: False} if the function was not created.
@ -216,29 +233,32 @@ def create_function(FunctionName, Runtime, Role, Handler, ZipFile=None,
''' '''
role_arn = _get_role_arn(Role, region=region, key=key, keyid=keyid, profile=profile) role_arn = _get_role_arn(Role, region=region, key=key,
keyid=keyid, profile=profile)
try: try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
if ZipFile: if ZipFile:
if S3Bucket or S3Key or S3ObjectVersion: if S3Bucket or S3Key or S3ObjectVersion:
raise SaltInvocationError('Either ZipFile must be specified, or ' raise SaltInvocationError('Either ZipFile must be specified, or '
'S3Bucket and S3Key must be provided.') 'S3Bucket and S3Key must be provided.')
code = { code = {
'ZipFile': _filedata(ZipFile), 'ZipFile': _filedata(ZipFile),
} }
else: else:
if not S3Bucket or not S3Key: if not S3Bucket or not S3Key:
raise SaltInvocationError('Either ZipFile must be specified, or ' raise SaltInvocationError('Either ZipFile must be specified, or '
'S3Bucket and S3Key must be provided.') 'S3Bucket and S3Key must be provided.')
code = { code = {
'S3Bucket': S3Bucket, 'S3Bucket': S3Bucket,
'S3Key': S3Key, 'S3Key': S3Key,
} }
if S3ObjectVersion: if S3ObjectVersion:
code['S3ObjectVersion'] = S3ObjectVersion code['S3ObjectVersion'] = S3ObjectVersion
kwargs = {} kwargs = {}
if VpcConfig is not None: if VpcConfig is not None:
kwargs['VpcConfig'] = VpcConfig kwargs['VpcConfig'] = VpcConfig
if Environment is not None:
kwargs['Environment'] = Environment
if WaitForRole: if WaitForRole:
retrycount = RoleRetries retrycount = RoleRetries
else: else:
@ -246,20 +266,23 @@ def create_function(FunctionName, Runtime, Role, Handler, ZipFile=None,
for retry in range(retrycount, 0, -1): for retry in range(retrycount, 0, -1):
try: try:
func = conn.create_function(FunctionName=FunctionName, Runtime=Runtime, Role=role_arn, Handler=Handler, func = conn.create_function(FunctionName=FunctionName, Runtime=Runtime, Role=role_arn, Handler=Handler,
Code=code, Description=Description, Timeout=Timeout, MemorySize=MemorySize, Code=code, Description=Description, Timeout=Timeout, MemorySize=MemorySize,
Publish=Publish, **kwargs) Publish=Publish, **kwargs)
except ClientError as e: except ClientError as e:
if retry > 1 and e.response.get('Error', {}).get('Code') == 'InvalidParameterValueException': if retry > 1 and e.response.get('Error', {}).get('Code') == 'InvalidParameterValueException':
log.info('Function not created but IAM role may not have propagated, will retry') log.info(
'Function not created but IAM role may not have propagated, will retry')
# exponential backoff # exponential backoff
time.sleep((2 ** (RoleRetries - retry)) + (random.randint(0, 1000) / 1000)) time.sleep((2 ** (RoleRetries - retry)) +
(random.randint(0, 1000) / 1000))
continue continue
else: else:
raise raise
else: else:
break break
if func: if func:
log.info('The newly created function name is {0}'.format(func['FunctionName'])) log.info('The newly created function name is {0}'.format(
func['FunctionName']))
return {'created': True, 'name': func['FunctionName']} return {'created': True, 'name': func['FunctionName']}
else: else:
@ -287,7 +310,8 @@ def delete_function(FunctionName, Qualifier=None, region=None, key=None, keyid=N
try: try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
if Qualifier: if Qualifier:
conn.delete_function(FunctionName=FunctionName, Qualifier=Qualifier) conn.delete_function(
FunctionName=FunctionName, Qualifier=Qualifier)
else: else:
conn.delete_function(FunctionName=FunctionName) conn.delete_function(FunctionName=FunctionName)
return {'deleted': True} return {'deleted': True}
@ -296,7 +320,7 @@ def delete_function(FunctionName, Qualifier=None, region=None, key=None, keyid=N
def describe_function(FunctionName, region=None, key=None, def describe_function(FunctionName, region=None, key=None,
keyid=None, profile=None): keyid=None, profile=None):
''' '''
Given a function name describe its properties. Given a function name describe its properties.
@ -312,11 +336,11 @@ def describe_function(FunctionName, region=None, key=None,
try: try:
func = _find_function(FunctionName, func = _find_function(FunctionName,
region=region, key=key, keyid=keyid, profile=profile) region=region, key=key, keyid=keyid, profile=profile)
if func: if func:
keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256', keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256',
'CodeSize', 'Description', 'Timeout', 'MemorySize', 'FunctionArn', 'CodeSize', 'Description', 'Timeout', 'MemorySize',
'LastModified', 'VpcConfig') 'FunctionArn', 'LastModified', 'VpcConfig', 'Environment')
return {'function': dict([(k, func.get(k)) for k in keys])} return {'function': dict([(k, func.get(k)) for k in keys])}
else: else:
return {'function': None} return {'function': None}
@ -325,12 +349,24 @@ def describe_function(FunctionName, region=None, key=None,
def update_function_config(FunctionName, Role=None, Handler=None, def update_function_config(FunctionName, Role=None, Handler=None,
Description=None, Timeout=None, MemorySize=None, Description=None, Timeout=None, MemorySize=None,
region=None, key=None, keyid=None, profile=None, VpcConfig=None, region=None, key=None, keyid=None, profile=None,
WaitForRole=False, RoleRetries=5): VpcConfig=None, WaitForRole=False, RoleRetries=5,
Environment=None):
''' '''
Update the named lambda function to the configuration. Update the named lambda function to the configuration.
Environment
The parent object that contains your environment's configuration
settings. This is a dictionary of the form:
{
'Variables': {
'VariableName': 'VariableValue'
}
}
.. versionadded:: Nitrogen
Returns {updated: true} if the function was updated and returns Returns {updated: true} if the function was updated and returns
{updated: False} if the function was not updated. {updated: False} if the function was not updated.
@ -347,7 +383,8 @@ def update_function_config(FunctionName, Role=None, Handler=None,
'Description': Description, 'Description': Description,
'Timeout': Timeout, 'Timeout': Timeout,
'MemorySize': MemorySize, 'MemorySize': MemorySize,
'VpcConfig': VpcConfig} 'VpcConfig': VpcConfig,
'Environment': Environment}
for val, var in six.iteritems(options): for val, var in six.iteritems(options):
if var: if var:
@ -366,9 +403,11 @@ def update_function_config(FunctionName, Role=None, Handler=None,
r = conn.update_function_configuration(**args) r = conn.update_function_configuration(**args)
except ClientError as e: except ClientError as e:
if retry > 1 and e.response.get('Error', {}).get('Code') == 'InvalidParameterValueException': if retry > 1 and e.response.get('Error', {}).get('Code') == 'InvalidParameterValueException':
log.info('Function not updated but IAM role may not have propagated, will retry') log.info(
'Function not updated but IAM role may not have propagated, will retry')
# exponential backoff # exponential backoff
time.sleep((2 ** (RoleRetries - retry)) + (random.randint(0, 1000) / 1000)) time.sleep((2 ** (RoleRetries - retry)) +
(random.randint(0, 1000) / 1000))
continue continue
else: else:
raise raise
@ -376,8 +415,8 @@ def update_function_config(FunctionName, Role=None, Handler=None,
break break
if r: if r:
keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256', keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256',
'CodeSize', 'Description', 'Timeout', 'MemorySize', 'FunctionArn', 'CodeSize', 'Description', 'Timeout', 'MemorySize',
'LastModified', 'VpcConfig') 'FunctionArn', 'LastModified', 'VpcConfig', 'Environment')
return {'updated': True, 'function': dict([(k, r.get(k)) for k in keys])} return {'updated': True, 'function': dict([(k, r.get(k)) for k in keys])}
else: else:
log.warning('Function was not updated') log.warning('Function was not updated')
@ -387,8 +426,8 @@ def update_function_config(FunctionName, Role=None, Handler=None,
def update_function_code(FunctionName, ZipFile=None, S3Bucket=None, S3Key=None, def update_function_code(FunctionName, ZipFile=None, S3Bucket=None, S3Key=None,
S3ObjectVersion=None, Publish=False, S3ObjectVersion=None, Publish=False,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Upload the given code to the named lambda function. Upload the given code to the named lambda function.
@ -408,14 +447,14 @@ def update_function_code(FunctionName, ZipFile=None, S3Bucket=None, S3Key=None,
if ZipFile: if ZipFile:
if S3Bucket or S3Key or S3ObjectVersion: if S3Bucket or S3Key or S3ObjectVersion:
raise SaltInvocationError('Either ZipFile must be specified, or ' raise SaltInvocationError('Either ZipFile must be specified, or '
'S3Bucket and S3Key must be provided.') 'S3Bucket and S3Key must be provided.')
r = conn.update_function_code(FunctionName=FunctionName, r = conn.update_function_code(FunctionName=FunctionName,
ZipFile=_filedata(ZipFile), ZipFile=_filedata(ZipFile),
Publish=Publish) Publish=Publish)
else: else:
if not S3Bucket or not S3Key: if not S3Bucket or not S3Key:
raise SaltInvocationError('Either ZipFile must be specified, or ' raise SaltInvocationError('Either ZipFile must be specified, or '
'S3Bucket and S3Key must be provided.') 'S3Bucket and S3Key must be provided.')
args = { args = {
'S3Bucket': S3Bucket, 'S3Bucket': S3Bucket,
'S3Key': S3Key, 'S3Key': S3Key,
@ -423,11 +462,11 @@ def update_function_code(FunctionName, ZipFile=None, S3Bucket=None, S3Key=None,
if S3ObjectVersion: if S3ObjectVersion:
args['S3ObjectVersion'] = S3ObjectVersion args['S3ObjectVersion'] = S3ObjectVersion
r = conn.update_function_code(FunctionName=FunctionName, r = conn.update_function_code(FunctionName=FunctionName,
Publish=Publish, **args) Publish=Publish, **args)
if r: if r:
keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256', keys = ('FunctionName', 'Runtime', 'Role', 'Handler', 'CodeSha256',
'CodeSize', 'Description', 'Timeout', 'MemorySize', 'FunctionArn', 'CodeSize', 'Description', 'Timeout', 'MemorySize',
'LastModified', 'VpcConfig') 'FunctionArn', 'LastModified', 'VpcConfig', 'Environment')
return {'updated': True, 'function': dict([(k, r.get(k)) for k in keys])} return {'updated': True, 'function': dict([(k, r.get(k)) for k in keys])}
else: else:
log.warning('Function was not updated') log.warning('Function was not updated')
@ -462,15 +501,15 @@ def add_permission(FunctionName, StatementId, Action, Principal, SourceArn=None,
if locals()[key] is not None: if locals()[key] is not None:
kwargs[key] = str(locals()[key]) kwargs[key] = str(locals()[key])
conn.add_permission(FunctionName=FunctionName, StatementId=StatementId, conn.add_permission(FunctionName=FunctionName, StatementId=StatementId,
Action=Action, Principal=str(Principal), Action=Action, Principal=str(Principal),
**kwargs) **kwargs)
return {'updated': True} return {'updated': True}
except ClientError as e: except ClientError as e:
return {'updated': False, 'error': salt.utils.boto3.get_error(e)} return {'updated': False, 'error': salt.utils.boto3.get_error(e)}
def remove_permission(FunctionName, StatementId, Qualifier=None, def remove_permission(FunctionName, StatementId, Qualifier=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Remove a permission from a lambda function. Remove a permission from a lambda function.
@ -491,7 +530,7 @@ def remove_permission(FunctionName, StatementId, Qualifier=None,
if Qualifier is not None: if Qualifier is not None:
kwargs['Qualifier'] = Qualifier kwargs['Qualifier'] = Qualifier
conn.remove_permission(FunctionName=FunctionName, StatementId=StatementId, conn.remove_permission(FunctionName=FunctionName, StatementId=StatementId,
**kwargs) **kwargs)
return {'updated': True} return {'updated': True}
except ClientError as e: except ClientError as e:
return {'updated': False, 'error': salt.utils.boto3.get_error(e)} return {'updated': False, 'error': salt.utils.boto3.get_error(e)}
@ -521,7 +560,7 @@ def get_permissions(FunctionName, Qualifier=None,
# The get_policy call is not symmetric with add/remove_permissions. So # The get_policy call is not symmetric with add/remove_permissions. So
# massage it until it is, for better ease of use. # massage it until it is, for better ease of use.
policy = conn.get_policy(FunctionName=FunctionName, policy = conn.get_policy(FunctionName=FunctionName,
**kwargs) **kwargs)
policy = policy.get('Policy', {}) policy = policy.get('Policy', {})
if isinstance(policy, six.string_types): if isinstance(policy, six.string_types):
policy = json.loads(policy) policy = json.loads(policy)
@ -540,9 +579,11 @@ def get_permissions(FunctionName, Qualifier=None,
'Principal': principal, 'Principal': principal,
} }
if 'ArnLike' in condition: if 'ArnLike' in condition:
permission['SourceArn'] = condition['ArnLike'].get('AWS:SourceArn') permission['SourceArn'] = condition[
'ArnLike'].get('AWS:SourceArn')
if 'StringEquals' in condition: if 'StringEquals' in condition:
permission['SourceAccount'] = condition['StringEquals'].get('AWS:SourceAccount') permission['SourceAccount'] = condition[
'StringEquals'].get('AWS:SourceAccount')
permissions[statement.get('Sid')] = permission permissions[statement.get('Sid')] = permission
return {'permissions': permissions} return {'permissions': permissions}
except ClientError as e: except ClientError as e:
@ -553,7 +594,7 @@ def get_permissions(FunctionName, Qualifier=None,
def list_function_versions(FunctionName, def list_function_versions(FunctionName,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
List the versions available for the given function. List the versions available for the given function.
@ -572,7 +613,7 @@ def list_function_versions(FunctionName,
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
vers = [] vers = []
for ret in salt.utils.boto3.paged_call(conn.list_versions_by_function, for ret in salt.utils.boto3.paged_call(conn.list_versions_by_function,
FunctionName=FunctionName): FunctionName=FunctionName):
vers.extend(ret['Versions']) vers.extend(ret['Versions'])
if not bool(vers): if not bool(vers):
log.warning('No versions found') log.warning('No versions found')
@ -582,7 +623,7 @@ def list_function_versions(FunctionName,
def create_alias(FunctionName, Name, FunctionVersion, Description="", def create_alias(FunctionName, Name, FunctionVersion, Description="",
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given a valid config, create an alias to a function. Given a valid config, create an alias to a function.
@ -599,9 +640,10 @@ def create_alias(FunctionName, Name, FunctionVersion, Description="",
try: try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
alias = conn.create_alias(FunctionName=FunctionName, Name=Name, alias = conn.create_alias(FunctionName=FunctionName, Name=Name,
FunctionVersion=FunctionVersion, Description=Description) FunctionVersion=FunctionVersion, Description=Description)
if alias: if alias:
log.info('The newly created alias name is {0}'.format(alias['Name'])) log.info(
'The newly created alias name is {0}'.format(alias['Name']))
return {'created': True, 'name': alias['Name']} return {'created': True, 'name': alias['Name']}
else: else:
@ -635,8 +677,7 @@ def delete_alias(FunctionName, Name, region=None, key=None, keyid=None, profile=
def _find_alias(FunctionName, Name, FunctionVersion=None, def _find_alias(FunctionName, Name, FunctionVersion=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given function name and alias name, find and return matching alias information. Given function name and alias name, find and return matching alias information.
''' '''
@ -656,7 +697,7 @@ def _find_alias(FunctionName, Name, FunctionVersion=None,
def alias_exists(FunctionName, Name, region=None, key=None, def alias_exists(FunctionName, Name, region=None, key=None,
keyid=None, profile=None): keyid=None, profile=None):
''' '''
Given a function name and alias name, check to see if the given alias exists. Given a function name and alias name, check to see if the given alias exists.
@ -673,14 +714,14 @@ def alias_exists(FunctionName, Name, region=None, key=None,
try: try:
alias = _find_alias(FunctionName, Name, alias = _find_alias(FunctionName, Name,
region=region, key=key, keyid=keyid, profile=profile) region=region, key=key, keyid=keyid, profile=profile)
return {'exists': bool(alias)} return {'exists': bool(alias)}
except ClientError as e: except ClientError as e:
return {'error': salt.utils.boto3.get_error(e)} return {'error': salt.utils.boto3.get_error(e)}
def describe_alias(FunctionName, Name, region=None, key=None, def describe_alias(FunctionName, Name, region=None, key=None,
keyid=None, profile=None): keyid=None, profile=None):
''' '''
Given a function name and alias name describe the properties of the alias. Given a function name and alias name describe the properties of the alias.
@ -696,7 +737,7 @@ def describe_alias(FunctionName, Name, region=None, key=None,
try: try:
alias = _find_alias(FunctionName, Name, alias = _find_alias(FunctionName, Name,
region=region, key=key, keyid=keyid, profile=profile) region=region, key=key, keyid=keyid, profile=profile)
if alias: if alias:
keys = ('AliasArn', 'Name', 'FunctionVersion', 'Description') keys = ('AliasArn', 'Name', 'FunctionVersion', 'Description')
return {'alias': dict([(k, alias.get(k)) for k in keys])} return {'alias': dict([(k, alias.get(k)) for k in keys])}
@ -707,7 +748,7 @@ def describe_alias(FunctionName, Name, region=None, key=None,
def update_alias(FunctionName, Name, FunctionVersion=None, Description=None, def update_alias(FunctionName, Name, FunctionVersion=None, Description=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Update the named alias to the configuration. Update the named alias to the configuration.
@ -741,8 +782,8 @@ def update_alias(FunctionName, Name, FunctionVersion=None, Description=None,
def create_event_source_mapping(EventSourceArn, FunctionName, StartingPosition, def create_event_source_mapping(EventSourceArn, FunctionName, StartingPosition,
Enabled=True, BatchSize=100, Enabled=True, BatchSize=100,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Identifies a stream as an event source for a Lambda function. It can be Identifies a stream as an event source for a Lambda function. It can be
either an Amazon Kinesis stream or an Amazon DynamoDB stream. AWS Lambda either an Amazon Kinesis stream or an Amazon DynamoDB stream. AWS Lambda
@ -766,7 +807,8 @@ def create_event_source_mapping(EventSourceArn, FunctionName, StartingPosition,
BatchSize=BatchSize, BatchSize=BatchSize,
StartingPosition=StartingPosition) StartingPosition=StartingPosition)
if obj: if obj:
log.info('The newly created event source mapping ID is {0}'.format(obj['UUID'])) log.info(
'The newly created event source mapping ID is {0}'.format(obj['UUID']))
return {'created': True, 'id': obj['UUID']} return {'created': True, 'id': obj['UUID']}
else: else:
@ -777,7 +819,7 @@ def create_event_source_mapping(EventSourceArn, FunctionName, StartingPosition,
def get_event_source_mapping_ids(EventSourceArn, FunctionName, def get_event_source_mapping_ids(EventSourceArn, FunctionName,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given an event source and function name, return a list of mapping IDs Given an event source and function name, return a list of mapping IDs
@ -793,28 +835,29 @@ def get_event_source_mapping_ids(EventSourceArn, FunctionName,
try: try:
mappings = [] mappings = []
for maps in salt.utils.boto3.paged_call(conn.list_event_source_mappings, for maps in salt.utils.boto3.paged_call(conn.list_event_source_mappings,
EventSourceArn=EventSourceArn, EventSourceArn=EventSourceArn,
FunctionName=FunctionName): FunctionName=FunctionName):
mappings.extend([mapping['UUID'] for mapping in maps['EventSourceMappings']]) mappings.extend([mapping['UUID']
for mapping in maps['EventSourceMappings']])
return mappings return mappings
except ClientError as e: except ClientError as e:
return {'error': salt.utils.boto3.get_error(e)} return {'error': salt.utils.boto3.get_error(e)}
def _get_ids(UUID=None, EventSourceArn=None, FunctionName=None, def _get_ids(UUID=None, EventSourceArn=None, FunctionName=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
if UUID: if UUID:
if EventSourceArn or FunctionName: if EventSourceArn or FunctionName:
raise SaltInvocationError('Either UUID must be specified, or ' raise SaltInvocationError('Either UUID must be specified, or '
'EventSourceArn and FunctionName must be provided.') 'EventSourceArn and FunctionName must be provided.')
return [UUID] return [UUID]
else: else:
if not EventSourceArn or not FunctionName: if not EventSourceArn or not FunctionName:
raise SaltInvocationError('Either UUID must be specified, or ' raise SaltInvocationError('Either UUID must be specified, or '
'EventSourceArn and FunctionName must be provided.') 'EventSourceArn and FunctionName must be provided.')
return get_event_source_mapping_ids(EventSourceArn=EventSourceArn, return get_event_source_mapping_ids(EventSourceArn=EventSourceArn,
FunctionName=FunctionName, FunctionName=FunctionName,
region=region, key=key, keyid=keyid, profile=profile) region=region, key=key, keyid=keyid, profile=profile)
def delete_event_source_mapping(UUID=None, EventSourceArn=None, FunctionName=None, def delete_event_source_mapping(UUID=None, EventSourceArn=None, FunctionName=None,
@ -834,7 +877,7 @@ def delete_event_source_mapping(UUID=None, EventSourceArn=None, FunctionName=Non
''' '''
ids = _get_ids(UUID, EventSourceArn=EventSourceArn, ids = _get_ids(UUID, EventSourceArn=EventSourceArn,
FunctionName=FunctionName) FunctionName=FunctionName)
try: try:
conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile) conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
for id in ids: for id in ids:
@ -845,8 +888,8 @@ def delete_event_source_mapping(UUID=None, EventSourceArn=None, FunctionName=Non
def event_source_mapping_exists(UUID=None, EventSourceArn=None, def event_source_mapping_exists(UUID=None, EventSourceArn=None,
FunctionName=None, FunctionName=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given an event source mapping ID or an event source ARN and FunctionName, Given an event source mapping ID or an event source ARN and FunctionName,
check whether the mapping exists. check whether the mapping exists.
@ -873,8 +916,8 @@ def event_source_mapping_exists(UUID=None, EventSourceArn=None,
def describe_event_source_mapping(UUID=None, EventSourceArn=None, def describe_event_source_mapping(UUID=None, EventSourceArn=None,
FunctionName=None, FunctionName=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Given an event source mapping ID or an event source ARN and FunctionName, Given an event source mapping ID or an event source ARN and FunctionName,
obtain the current settings of that mapping. obtain the current settings of that mapping.
@ -890,7 +933,7 @@ def describe_event_source_mapping(UUID=None, EventSourceArn=None,
''' '''
ids = _get_ids(UUID, EventSourceArn=EventSourceArn, ids = _get_ids(UUID, EventSourceArn=EventSourceArn,
FunctionName=FunctionName) FunctionName=FunctionName)
if len(ids) < 1: if len(ids) < 1:
return {'event_source_mapping': None} return {'event_source_mapping': None}
@ -910,8 +953,8 @@ def describe_event_source_mapping(UUID=None, EventSourceArn=None,
def update_event_source_mapping(UUID, def update_event_source_mapping(UUID,
FunctionName=None, Enabled=None, BatchSize=None, FunctionName=None, Enabled=None, BatchSize=None,
region=None, key=None, keyid=None, profile=None): region=None, key=None, keyid=None, profile=None):
''' '''
Update the event source mapping identified by the UUID. Update the event source mapping identified by the UUID.

View File

@ -37,6 +37,7 @@ import os
try: try:
import boto3 import boto3
from botocore.exceptions import ClientError from botocore.exceptions import ClientError
from botocore import __version__ as found_botocore_version
HAS_BOTO = True HAS_BOTO = True
except ImportError: except ImportError:
HAS_BOTO = False HAS_BOTO = False
@ -51,17 +52,19 @@ if 'SuSE' in platform.dist():
# which was added in boto 2.8.0 # which was added in boto 2.8.0
# https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12 # https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
required_boto3_version = '1.2.1' required_boto3_version = '1.2.1'
required_botocore_version = '1.5.2'
region = 'us-east-1' region = 'us-east-1'
access_key = 'GKTADJGHEIQSXMKKRBJ08H' access_key = 'GKTADJGHEIQSXMKKRBJ08H'
secret_key = 'askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs' secret_key = 'askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs'
conn_parameters = {'region': region, 'key': access_key, 'keyid': secret_key, 'profile': {}} conn_parameters = {'region': region, 'key': access_key,
'keyid': secret_key, 'profile': {}}
error_message = 'An error occurred (101) when calling the {0} operation: Test-defined error' error_message = 'An error occurred (101) when calling the {0} operation: Test-defined error'
error_content = { error_content = {
'Error': { 'Error': {
'Code': 101, 'Code': 101,
'Message': "Test-defined error" 'Message': "Test-defined error"
} }
} }
function_ret = dict(FunctionName='testfunction', function_ret = dict(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
@ -74,7 +77,8 @@ function_ret = dict(FunctionName='testfunction',
CodeSize=199, CodeSize=199,
FunctionArn='arn:lambda:us-east-1:1234:Something', FunctionArn='arn:lambda:us-east-1:1234:Something',
LastModified='yes', LastModified='yes',
VpcConfig=None) VpcConfig=None,
Environment=None)
alias_ret = dict(AliasArn='arn:lambda:us-east-1:1234:Something', alias_ret = dict(AliasArn='arn:lambda:us-east-1:1234:Something',
Name='testalias', Name='testalias',
FunctionVersion='3', FunctionVersion='3',
@ -108,6 +112,8 @@ def _has_required_boto():
return False return False
elif LooseVersion(boto3.__version__) < LooseVersion(required_boto3_version): elif LooseVersion(boto3.__version__) < LooseVersion(required_boto3_version):
return False return False
elif LooseVersion(found_botocore_version) < LooseVersion(required_botocore_version):
return False
else: else:
return True return True
@ -127,7 +133,8 @@ class BotoLambdaTestCaseBase(TestCase):
# connections keep getting cached from prior tests, can't find the # connections keep getting cached from prior tests, can't find the
# correct context object to clear it. So randomize the cache key, to prevent any # correct context object to clear it. So randomize the cache key, to prevent any
# cache hits # cache hits
conn_parameters['key'] = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(50)) conn_parameters['key'] = ''.join(random.choice(
string.ascii_lowercase + string.digits) for _ in range(50))
self.patcher = patch('boto3.session.Session') self.patcher = patch('boto3.session.Session')
self.addCleanup(self.patcher.stop) self.addCleanup(self.patcher.stop)
@ -139,6 +146,7 @@ class BotoLambdaTestCaseBase(TestCase):
class TempZipFile(object): class TempZipFile(object):
def __enter__(self): def __enter__(self):
with NamedTemporaryFile(suffix='.zip', prefix='salt_test_', delete=False) as tmp: with NamedTemporaryFile(suffix='.zip', prefix='salt_test_', delete=False) as tmp:
to_write = '###\n' to_write = '###\n'
@ -166,7 +174,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
Tests checking lambda function existence when the lambda function already exists Tests checking lambda function existence when the lambda function already exists
''' '''
self.conn.list_functions.return_value = {'Functions': [function_ret]} self.conn.list_functions.return_value = {'Functions': [function_ret]}
func_exists_result = boto_lambda.function_exists(FunctionName=function_ret['FunctionName'], **conn_parameters) func_exists_result = boto_lambda.function_exists(
FunctionName=function_ret['FunctionName'], **conn_parameters)
self.assertTrue(func_exists_result['exists']) self.assertTrue(func_exists_result['exists'])
@ -175,7 +184,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
Tests checking lambda function existence when the lambda function does not exist Tests checking lambda function existence when the lambda function does not exist
''' '''
self.conn.list_functions.return_value = {'Functions': [function_ret]} self.conn.list_functions.return_value = {'Functions': [function_ret]}
func_exists_result = boto_lambda.function_exists(FunctionName='myfunc', **conn_parameters) func_exists_result = boto_lambda.function_exists(
FunctionName='myfunc', **conn_parameters)
self.assertFalse(func_exists_result['exists']) self.assertFalse(func_exists_result['exists'])
@ -183,10 +193,13 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
Tests checking lambda function existence when boto returns an error Tests checking lambda function existence when boto returns an error
''' '''
self.conn.list_functions.side_effect = ClientError(error_content, 'list_functions') self.conn.list_functions.side_effect = ClientError(
func_exists_result = boto_lambda.function_exists(FunctionName='myfunc', **conn_parameters) error_content, 'list_functions')
func_exists_result = boto_lambda.function_exists(
FunctionName='myfunc', **conn_parameters)
self.assertEqual(func_exists_result.get('error', {}).get('message'), error_message.format('list_functions')) self.assertEqual(func_exists_result.get('error', {}).get(
'message'), error_message.format('list_functions'))
def test_that_when_creating_a_function_from_zipfile_succeeds_the_create_function_method_returns_true(self): def test_that_when_creating_a_function_from_zipfile_succeeds_the_create_function_method_returns_true(self):
''' '''
@ -196,11 +209,11 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
with TempZipFile() as zipfile: with TempZipFile() as zipfile:
self.conn.create_function.return_value = function_ret self.conn.create_function.return_value = function_ret
lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction', lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
Role='myrole', Role='myrole',
Handler='file.method', Handler='file.method',
ZipFile=zipfile, ZipFile=zipfile,
**conn_parameters) **conn_parameters)
self.assertTrue(lambda_creation_result['created']) self.assertTrue(lambda_creation_result['created'])
@ -211,12 +224,12 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.create_function.return_value = function_ret self.conn.create_function.return_value = function_ret
lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction', lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
Role='myrole', Role='myrole',
Handler='file.method', Handler='file.method',
S3Bucket='bucket', S3Bucket='bucket',
S3Key='key', S3Key='key',
**conn_parameters) **conn_parameters)
self.assertTrue(lambda_creation_result['created']) self.assertTrue(lambda_creation_result['created'])
@ -226,12 +239,12 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
with self.assertRaisesRegexp(SaltInvocationError, with self.assertRaisesRegexp(SaltInvocationError,
'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'): 'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'):
lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction', lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
Role='myrole', Role='myrole',
Handler='file.method', Handler='file.method',
**conn_parameters) **conn_parameters)
def test_that_when_creating_a_function_with_zipfile_and_s3_raises_a_salt_invocation_error(self): def test_that_when_creating_a_function_with_zipfile_and_s3_raises_a_salt_invocation_error(self):
''' '''
@ -239,31 +252,33 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
with self.assertRaisesRegexp(SaltInvocationError, with self.assertRaisesRegexp(SaltInvocationError,
'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'): 'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'):
with TempZipFile() as zipfile: with TempZipFile() as zipfile:
lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction', lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
Role='myrole', Role='myrole',
Handler='file.method', Handler='file.method',
ZipFile=zipfile, ZipFile=zipfile,
S3Bucket='bucket', S3Bucket='bucket',
S3Key='key', S3Key='key',
**conn_parameters) **conn_parameters)
def test_that_when_creating_a_function_fails_the_create_function_method_returns_error(self): def test_that_when_creating_a_function_fails_the_create_function_method_returns_error(self):
''' '''
tests False function not created. tests False function not created.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.create_function.side_effect = ClientError(error_content, 'create_function') self.conn.create_function.side_effect = ClientError(
error_content, 'create_function')
with TempZipFile() as zipfile: with TempZipFile() as zipfile:
lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction', lambda_creation_result = boto_lambda.create_function(FunctionName='testfunction',
Runtime='python2.7', Runtime='python2.7',
Role='myrole', Role='myrole',
Handler='file.method', Handler='file.method',
ZipFile=zipfile, ZipFile=zipfile,
**conn_parameters) **conn_parameters)
self.assertEqual(lambda_creation_result.get('error', {}).get('message'), error_message.format('create_function')) self.assertEqual(lambda_creation_result.get('error', {}).get(
'message'), error_message.format('create_function'))
def test_that_when_deleting_a_function_succeeds_the_delete_function_method_returns_true(self): def test_that_when_deleting_a_function_succeeds_the_delete_function_method_returns_true(self):
''' '''
@ -271,8 +286,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
result = boto_lambda.delete_function(FunctionName='testfunction', result = boto_lambda.delete_function(FunctionName='testfunction',
Qualifier=1, Qualifier=1,
**conn_parameters) **conn_parameters)
self.assertTrue(result['deleted']) self.assertTrue(result['deleted'])
@ -281,9 +296,10 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
tests False function not deleted. tests False function not deleted.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.delete_function.side_effect = ClientError(error_content, 'delete_function') self.conn.delete_function.side_effect = ClientError(
error_content, 'delete_function')
result = boto_lambda.delete_function(FunctionName='testfunction', result = boto_lambda.delete_function(FunctionName='testfunction',
**conn_parameters) **conn_parameters)
self.assertFalse(result['deleted']) self.assertFalse(result['deleted'])
def test_that_when_describing_function_it_returns_the_dict_of_properties_returns_true(self): def test_that_when_describing_function_it_returns_the_dict_of_properties_returns_true(self):
@ -293,7 +309,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
self.conn.list_functions.return_value = {'Functions': [function_ret]} self.conn.list_functions.return_value = {'Functions': [function_ret]}
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
result = boto_lambda.describe_function(FunctionName=function_ret['FunctionName'], **conn_parameters) result = boto_lambda.describe_function(
FunctionName=function_ret['FunctionName'], **conn_parameters)
self.assertEqual(result, {'function': function_ret}) self.assertEqual(result, {'function': function_ret})
@ -303,7 +320,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
self.conn.list_functions.return_value = {'Functions': []} self.conn.list_functions.return_value = {'Functions': []}
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
result = boto_lambda.describe_function(FunctionName='testfunction', **conn_parameters) result = boto_lambda.describe_function(
FunctionName='testfunction', **conn_parameters)
self.assertFalse(result['function']) self.assertFalse(result['function'])
@ -311,8 +329,10 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
Tests describing parameters failure Tests describing parameters failure
''' '''
self.conn.list_functions.side_effect = ClientError(error_content, 'list_functions') self.conn.list_functions.side_effect = ClientError(
result = boto_lambda.describe_function(FunctionName='testfunction', **conn_parameters) error_content, 'list_functions')
result = boto_lambda.describe_function(
FunctionName='testfunction', **conn_parameters)
self.assertTrue('error' in result) self.assertTrue('error' in result)
def test_that_when_updating_a_function_succeeds_the_update_function_method_returns_true(self): def test_that_when_updating_a_function_succeeds_the_update_function_method_returns_true(self):
@ -321,7 +341,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.update_function_config.return_value = function_ret self.conn.update_function_config.return_value = function_ret
result = boto_lambda.update_function_config(FunctionName=function_ret['FunctionName'], Role='myrole', **conn_parameters) result = boto_lambda.update_function_config(
FunctionName=function_ret['FunctionName'], Role='myrole', **conn_parameters)
self.assertTrue(result['updated']) self.assertTrue(result['updated'])
@ -330,11 +351,13 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
tests False function not updated. tests False function not updated.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.update_function_configuration.side_effect = ClientError(error_content, 'update_function') self.conn.update_function_configuration.side_effect = ClientError(
error_content, 'update_function')
result = boto_lambda.update_function_config(FunctionName='testfunction', result = boto_lambda.update_function_config(FunctionName='testfunction',
Role='myrole', Role='myrole',
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('update_function')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('update_function'))
def test_that_when_updating_function_code_from_zipfile_succeeds_the_update_function_method_returns_true(self): def test_that_when_updating_function_code_from_zipfile_succeeds_the_update_function_method_returns_true(self):
''' '''
@ -343,7 +366,8 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
with TempZipFile() as zipfile: with TempZipFile() as zipfile:
self.conn.update_function_code.return_value = function_ret self.conn.update_function_code.return_value = function_ret
result = boto_lambda.update_function_code(FunctionName=function_ret['FunctionName'], ZipFile=zipfile, **conn_parameters) result = boto_lambda.update_function_code(
FunctionName=function_ret['FunctionName'], ZipFile=zipfile, **conn_parameters)
self.assertTrue(result['updated']) self.assertTrue(result['updated'])
@ -354,9 +378,9 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.update_function_code.return_value = function_ret self.conn.update_function_code.return_value = function_ret
result = boto_lambda.update_function_code(FunctionName='testfunction', result = boto_lambda.update_function_code(FunctionName='testfunction',
S3Bucket='bucket', S3Bucket='bucket',
S3Key='key', S3Key='key',
**conn_parameters) **conn_parameters)
self.assertTrue(result['updated']) self.assertTrue(result['updated'])
@ -366,30 +390,33 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
with self.assertRaisesRegexp(SaltInvocationError, with self.assertRaisesRegexp(SaltInvocationError,
'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'): 'Either ZipFile must be specified, or S3Bucket and S3Key must be provided.'):
result = boto_lambda.update_function_code(FunctionName='testfunction', result = boto_lambda.update_function_code(FunctionName='testfunction',
**conn_parameters) **conn_parameters)
def test_that_when_updating_function_code_fails_the_update_function_method_returns_error(self): def test_that_when_updating_function_code_fails_the_update_function_method_returns_error(self):
''' '''
tests False function not updated. tests False function not updated.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.update_function_code.side_effect = ClientError(error_content, 'update_function_code') self.conn.update_function_code.side_effect = ClientError(
error_content, 'update_function_code')
result = boto_lambda.update_function_code(FunctionName='testfunction', result = boto_lambda.update_function_code(FunctionName='testfunction',
S3Bucket='bucket', S3Bucket='bucket',
S3Key='key', S3Key='key',
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('update_function_code')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('update_function_code'))
def test_that_when_listing_function_versions_succeeds_the_list_function_versions_method_returns_true(self): def test_that_when_listing_function_versions_succeeds_the_list_function_versions_method_returns_true(self):
''' '''
tests True function versions listed. tests True function versions listed.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.list_versions_by_function.return_value = {'Versions': [function_ret]} self.conn.list_versions_by_function.return_value = {
'Versions': [function_ret]}
result = boto_lambda.list_function_versions(FunctionName='testfunction', result = boto_lambda.list_function_versions(FunctionName='testfunction',
**conn_parameters) **conn_parameters)
self.assertTrue(result['Versions']) self.assertTrue(result['Versions'])
@ -400,7 +427,7 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.list_versions_by_function.return_value = {'Versions': []} self.conn.list_versions_by_function.return_value = {'Versions': []}
result = boto_lambda.list_function_versions(FunctionName='testfunction', result = boto_lambda.list_function_versions(FunctionName='testfunction',
**conn_parameters) **conn_parameters)
self.assertFalse(result['Versions']) self.assertFalse(result['Versions'])
def test_that_when_listing_function_versions_fails_the_list_function_versions_method_returns_error(self): def test_that_when_listing_function_versions_fails_the_list_function_versions_method_returns_error(self):
@ -408,10 +435,12 @@ class BotoLambdaFunctionTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin
tests False function versions error. tests False function versions error.
''' '''
with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}): with patch.dict(boto_lambda.__salt__, {'boto_iam.get_account_id': MagicMock(return_value='1234')}):
self.conn.list_versions_by_function.side_effect = ClientError(error_content, 'list_versions_by_function') self.conn.list_versions_by_function.side_effect = ClientError(
error_content, 'list_versions_by_function')
result = boto_lambda.list_function_versions(FunctionName='testfunction', result = boto_lambda.list_function_versions(FunctionName='testfunction',
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('list_versions_by_function')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('list_versions_by_function'))
@skipIf(HAS_BOTO is False, 'The boto module must be installed.') @skipIf(HAS_BOTO is False, 'The boto module must be installed.')
@ -423,15 +452,17 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
TestCase for salt.modules.boto_lambda module aliases TestCase for salt.modules.boto_lambda module aliases
''' '''
def test_that_when_creating_an_alias_succeeds_the_create_alias_method_returns_true(self): def test_that_when_creating_an_alias_succeeds_the_create_alias_method_returns_true(self):
''' '''
tests True alias created. tests True alias created.
''' '''
self.conn.create_alias.return_value = alias_ret self.conn.create_alias.return_value = alias_ret
result = boto_lambda.create_alias(FunctionName='testfunction', result = boto_lambda.create_alias(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
FunctionVersion=alias_ret['FunctionVersion'], FunctionVersion=alias_ret[
**conn_parameters) 'FunctionVersion'],
**conn_parameters)
self.assertTrue(result['created']) self.assertTrue(result['created'])
@ -439,12 +470,15 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
tests False alias not created. tests False alias not created.
''' '''
self.conn.create_alias.side_effect = ClientError(error_content, 'create_alias') self.conn.create_alias.side_effect = ClientError(
error_content, 'create_alias')
result = boto_lambda.create_alias(FunctionName='testfunction', result = boto_lambda.create_alias(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
FunctionVersion=alias_ret['FunctionVersion'], FunctionVersion=alias_ret[
**conn_parameters) 'FunctionVersion'],
self.assertEqual(result.get('error', {}).get('message'), error_message.format('create_alias')) **conn_parameters)
self.assertEqual(result.get('error', {}).get(
'message'), error_message.format('create_alias'))
def test_that_when_deleting_an_alias_succeeds_the_delete_alias_method_returns_true(self): def test_that_when_deleting_an_alias_succeeds_the_delete_alias_method_returns_true(self):
''' '''
@ -460,7 +494,8 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
tests False alias not deleted. tests False alias not deleted.
''' '''
self.conn.delete_alias.side_effect = ClientError(error_content, 'delete_alias') self.conn.delete_alias.side_effect = ClientError(
error_content, 'delete_alias')
result = boto_lambda.delete_alias(FunctionName='testfunction', result = boto_lambda.delete_alias(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
**conn_parameters) **conn_parameters)
@ -491,12 +526,14 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
Tests checking lambda alias existence when boto returns an error Tests checking lambda alias existence when boto returns an error
''' '''
self.conn.list_aliases.side_effect = ClientError(error_content, 'list_aliases') self.conn.list_aliases.side_effect = ClientError(
error_content, 'list_aliases')
result = boto_lambda.alias_exists(FunctionName='testfunction', result = boto_lambda.alias_exists(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('list_aliases')) self.assertEqual(result.get('error', {}).get(
'message'), error_message.format('list_aliases'))
def test_that_when_describing_alias_it_returns_the_dict_of_properties_returns_true(self): def test_that_when_describing_alias_it_returns_the_dict_of_properties_returns_true(self):
''' '''
@ -525,7 +562,8 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
Tests describing parameters failure Tests describing parameters failure
''' '''
self.conn.list_aliases.side_effect = ClientError(error_content, 'list_aliases') self.conn.list_aliases.side_effect = ClientError(
error_content, 'list_aliases')
result = boto_lambda.describe_alias(FunctionName='testfunction', result = boto_lambda.describe_alias(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
**conn_parameters) **conn_parameters)
@ -547,11 +585,13 @@ class BotoLambdaAliasTestCase(BotoLambdaTestCaseBase, BotoLambdaTestCaseMixin):
''' '''
tests False alias not updated. tests False alias not updated.
''' '''
self.conn.update_alias.side_effect = ClientError(error_content, 'update_alias') self.conn.update_alias.side_effect = ClientError(
error_content, 'update_alias')
result = boto_lambda.update_alias(FunctionName='testfunction', result = boto_lambda.update_alias(FunctionName='testfunction',
Name=alias_ret['Name'], Name=alias_ret['Name'],
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('update_alias')) self.assertEqual(result.get('error', {}).get(
'message'), error_message.format('update_alias'))
@skipIf(HAS_BOTO is False, 'The boto module must be installed.') @skipIf(HAS_BOTO is False, 'The boto module must be installed.')
@ -563,16 +603,17 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
TestCase for salt.modules.boto_lambda module mappings TestCase for salt.modules.boto_lambda module mappings
''' '''
def test_that_when_creating_a_mapping_succeeds_the_create_event_source_mapping_method_returns_true(self): def test_that_when_creating_a_mapping_succeeds_the_create_event_source_mapping_method_returns_true(self):
''' '''
tests True mapping created. tests True mapping created.
''' '''
self.conn.create_event_source_mapping.return_value = event_source_mapping_ret self.conn.create_event_source_mapping.return_value = event_source_mapping_ret
result = boto_lambda.create_event_source_mapping( result = boto_lambda.create_event_source_mapping(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
StartingPosition='LATEST', StartingPosition='LATEST',
**conn_parameters) **conn_parameters)
self.assertTrue(result['created']) self.assertTrue(result['created'])
@ -580,12 +621,13 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests False mapping not created. tests False mapping not created.
''' '''
self.conn.create_event_source_mapping.side_effect = ClientError(error_content, 'create_event_source_mapping') self.conn.create_event_source_mapping.side_effect = ClientError(
error_content, 'create_event_source_mapping')
result = boto_lambda.create_event_source_mapping( result = boto_lambda.create_event_source_mapping(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
StartingPosition='LATEST', StartingPosition='LATEST',
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), self.assertEqual(result.get('error', {}).get('message'),
error_message.format('create_event_source_mapping')) error_message.format('create_event_source_mapping'))
@ -593,11 +635,12 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests True mapping ids listed. tests True mapping ids listed.
''' '''
self.conn.list_event_source_mappings.return_value = {'EventSourceMappings': [event_source_mapping_ret]} self.conn.list_event_source_mappings.return_value = {
'EventSourceMappings': [event_source_mapping_ret]}
result = boto_lambda.get_event_source_mapping_ids( result = boto_lambda.get_event_source_mapping_ids(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertTrue(result) self.assertTrue(result)
@ -605,31 +648,34 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests False no mapping ids listed. tests False no mapping ids listed.
''' '''
self.conn.list_event_source_mappings.return_value = {'EventSourceMappings': []} self.conn.list_event_source_mappings.return_value = {
'EventSourceMappings': []}
result = boto_lambda.get_event_source_mapping_ids( result = boto_lambda.get_event_source_mapping_ids(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertFalse(result) self.assertFalse(result)
def test_that_when_listing_event_source_mapping_ids_fails_the_get_event_source_mapping_ids_method_returns_error(self): def test_that_when_listing_event_source_mapping_ids_fails_the_get_event_source_mapping_ids_method_returns_error(self):
''' '''
tests False mapping ids error. tests False mapping ids error.
''' '''
self.conn.list_event_source_mappings.side_effect = ClientError(error_content, 'list_event_source_mappings') self.conn.list_event_source_mappings.side_effect = ClientError(
error_content, 'list_event_source_mappings')
result = boto_lambda.get_event_source_mapping_ids( result = boto_lambda.get_event_source_mapping_ids(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('list_event_source_mappings')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('list_event_source_mappings'))
def test_that_when_deleting_an_event_source_mapping_by_UUID_succeeds_the_delete_event_source_mapping_method_returns_true(self): def test_that_when_deleting_an_event_source_mapping_by_UUID_succeeds_the_delete_event_source_mapping_method_returns_true(self):
''' '''
tests True mapping deleted. tests True mapping deleted.
''' '''
result = boto_lambda.delete_event_source_mapping( result = boto_lambda.delete_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertTrue(result['deleted']) self.assertTrue(result['deleted'])
@skipIf(True, 'This appears to leak memory and crash the unit test suite') @skipIf(True, 'This appears to leak memory and crash the unit test suite')
@ -637,11 +683,12 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests True mapping deleted. tests True mapping deleted.
''' '''
self.conn.list_event_source_mappings.return_value = {'EventSourceMappings': [event_source_mapping_ret]} self.conn.list_event_source_mappings.return_value = {
'EventSourceMappings': [event_source_mapping_ret]}
result = boto_lambda.delete_event_source_mapping( result = boto_lambda.delete_event_source_mapping(
EventSourceArn=event_source_mapping_ret['EventSourceArn'], EventSourceArn=event_source_mapping_ret['EventSourceArn'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertTrue(result['deleted']) self.assertTrue(result['deleted'])
def test_that_when_deleting_an_event_source_mapping_without_identifier_the_delete_event_source_mapping_method_raises_saltinvocationexception(self): def test_that_when_deleting_an_event_source_mapping_without_identifier_the_delete_event_source_mapping_method_raises_saltinvocationexception(self):
@ -656,9 +703,10 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests False mapping not deleted. tests False mapping not deleted.
''' '''
self.conn.delete_event_source_mapping.side_effect = ClientError(error_content, 'delete_event_source_mapping') self.conn.delete_event_source_mapping.side_effect = ClientError(
error_content, 'delete_event_source_mapping')
result = boto_lambda.delete_event_source_mapping(UUID=event_source_mapping_ret['UUID'], result = boto_lambda.delete_event_source_mapping(UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertFalse(result['deleted']) self.assertFalse(result['deleted'])
def test_that_when_checking_if_an_event_source_mapping_exists_and_the_event_source_mapping_exists_the_event_source_mapping_exists_method_returns_true(self): def test_that_when_checking_if_an_event_source_mapping_exists_and_the_event_source_mapping_exists_the_event_source_mapping_exists_method_returns_true(self):
@ -668,8 +716,8 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
self.conn.get_event_source_mapping.return_value = event_source_mapping_ret self.conn.get_event_source_mapping.return_value = event_source_mapping_ret
result = boto_lambda.event_source_mapping_exists( result = boto_lambda.event_source_mapping_exists(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertTrue(result['exists']) self.assertTrue(result['exists'])
def test_that_when_checking_if_an_event_source_mapping_exists_and_the_event_source_mapping_does_not_exist_the_event_source_mapping_exists_method_returns_false(self): def test_that_when_checking_if_an_event_source_mapping_exists_and_the_event_source_mapping_does_not_exist_the_event_source_mapping_exists_method_returns_false(self):
@ -679,19 +727,21 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
self.conn.get_event_source_mapping.return_value = None self.conn.get_event_source_mapping.return_value = None
result = boto_lambda.event_source_mapping_exists( result = boto_lambda.event_source_mapping_exists(
UUID='other_UUID', UUID='other_UUID',
**conn_parameters) **conn_parameters)
self.assertFalse(result['exists']) self.assertFalse(result['exists'])
def test_that_when_checking_if_an_event_source_mapping_exists_and_boto3_returns_an_error_the_event_source_mapping_exists_method_returns_error(self): def test_that_when_checking_if_an_event_source_mapping_exists_and_boto3_returns_an_error_the_event_source_mapping_exists_method_returns_error(self):
''' '''
Tests checking lambda event_source_mapping existence when boto returns an error Tests checking lambda event_source_mapping existence when boto returns an error
''' '''
self.conn.get_event_source_mapping.side_effect = ClientError(error_content, 'list_event_source_mappings') self.conn.get_event_source_mapping.side_effect = ClientError(
error_content, 'list_event_source_mappings')
result = boto_lambda.event_source_mapping_exists( result = boto_lambda.event_source_mapping_exists(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('list_event_source_mappings')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('list_event_source_mappings'))
def test_that_when_describing_event_source_mapping_it_returns_the_dict_of_properties_returns_true(self): def test_that_when_describing_event_source_mapping_it_returns_the_dict_of_properties_returns_true(self):
''' '''
@ -699,9 +749,10 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
self.conn.get_event_source_mapping.return_value = event_source_mapping_ret self.conn.get_event_source_mapping.return_value = event_source_mapping_ret
result = boto_lambda.describe_event_source_mapping( result = boto_lambda.describe_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertEqual(result, {'event_source_mapping': event_source_mapping_ret}) self.assertEqual(
result, {'event_source_mapping': event_source_mapping_ret})
def test_that_when_describing_event_source_mapping_it_returns_the_dict_of_properties_returns_false(self): def test_that_when_describing_event_source_mapping_it_returns_the_dict_of_properties_returns_false(self):
''' '''
@ -709,18 +760,19 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
self.conn.get_event_source_mapping.return_value = None self.conn.get_event_source_mapping.return_value = None
result = boto_lambda.describe_event_source_mapping( result = boto_lambda.describe_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertFalse(result['event_source_mapping']) self.assertFalse(result['event_source_mapping'])
def test_that_when_describing_event_source_mapping_on_client_error_it_returns_error(self): def test_that_when_describing_event_source_mapping_on_client_error_it_returns_error(self):
''' '''
Tests describing parameters failure Tests describing parameters failure
''' '''
self.conn.get_event_source_mapping.side_effect = ClientError(error_content, 'get_event_source_mapping') self.conn.get_event_source_mapping.side_effect = ClientError(
error_content, 'get_event_source_mapping')
result = boto_lambda.describe_event_source_mapping( result = boto_lambda.describe_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
**conn_parameters) **conn_parameters)
self.assertTrue('error' in result) self.assertTrue('error' in result)
def test_that_when_updating_an_event_source_mapping_succeeds_the_update_event_source_mapping_method_returns_true(self): def test_that_when_updating_an_event_source_mapping_succeeds_the_update_event_source_mapping_method_returns_true(self):
@ -729,9 +781,9 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
self.conn.update_event_source_mapping.return_value = event_source_mapping_ret self.conn.update_event_source_mapping.return_value = event_source_mapping_ret
result = boto_lambda.update_event_source_mapping( result = boto_lambda.update_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertTrue(result['updated']) self.assertTrue(result['updated'])
@ -739,12 +791,14 @@ class BotoLambdaEventSourceMappingTestCase(BotoLambdaTestCaseBase, BotoLambdaTes
''' '''
tests False event_source_mapping not updated. tests False event_source_mapping not updated.
''' '''
self.conn.update_event_source_mapping.side_effect = ClientError(error_content, 'update_event_source_mapping') self.conn.update_event_source_mapping.side_effect = ClientError(
error_content, 'update_event_source_mapping')
result = boto_lambda.update_event_source_mapping( result = boto_lambda.update_event_source_mapping(
UUID=event_source_mapping_ret['UUID'], UUID=event_source_mapping_ret['UUID'],
FunctionName=event_source_mapping_ret['FunctionArn'], FunctionName=event_source_mapping_ret['FunctionArn'],
**conn_parameters) **conn_parameters)
self.assertEqual(result.get('error', {}).get('message'), error_message.format('update_event_source_mapping')) self.assertEqual(result.get('error', {}).get('message'),
error_message.format('update_event_source_mapping'))
if __name__ == '__main__': if __name__ == '__main__':