mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
Start using ClientRequestTokens in event lists (#31997)
* Start using ClientRequestTokens in event lists * Include request token in all reqs that support it (basically all but check mode/changeset) * Update placebo recordings * Add comments for CRQ popping
This commit is contained in:
parent
70c58e74ab
commit
11c225e039
33 changed files with 550 additions and 913 deletions
|
@ -223,6 +223,7 @@ stack_outputs:
|
|||
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
import traceback
|
||||
from hashlib import sha1
|
||||
|
||||
|
@ -237,15 +238,25 @@ import ansible.module_utils.ec2
|
|||
# import a class, otherwise we'll use a fully qualified path
|
||||
from ansible.module_utils.ec2 import AWSRetry, boto_exception
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils._text import to_bytes, to_native
|
||||
|
||||
|
||||
def get_stack_events(cfn, stack_name):
|
||||
def get_stack_events(cfn, stack_name, token_filter=None):
|
||||
'''This event data was never correct, it worked as a side effect. So the v2.3 format is different.'''
|
||||
ret = {'events':[], 'log':[]}
|
||||
|
||||
try:
|
||||
events = cfn.describe_stack_events(StackName=stack_name)
|
||||
pg = cfn.get_paginator(
|
||||
'describe_stack_events'
|
||||
).paginate(
|
||||
StackName=stack_name
|
||||
)
|
||||
if token_filter is not None:
|
||||
events = list(pg.search(
|
||||
"StackEvents[?ClientRequestToken == '{0}']".format(token_filter)
|
||||
))
|
||||
else:
|
||||
events = list(pg)
|
||||
except (botocore.exceptions.ValidationError, botocore.exceptions.ClientError) as err:
|
||||
error_msg = boto_exception(err)
|
||||
if 'does not exist' in error_msg:
|
||||
|
@ -255,7 +266,7 @@ def get_stack_events(cfn, stack_name):
|
|||
ret['log'].append('Unknown error: ' + str(error_msg))
|
||||
return ret
|
||||
|
||||
for e in events.get('StackEvents', []):
|
||||
for e in events:
|
||||
eventline = 'StackEvent {ResourceType} {LogicalResourceId} {ResourceStatus}'.format(**e)
|
||||
ret['events'].append(eventline)
|
||||
|
||||
|
@ -281,7 +292,7 @@ def create_stack(module, stack_params, cfn):
|
|||
|
||||
try:
|
||||
cfn.create_stack(**stack_params)
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'CREATE')
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'CREATE', stack_params['ClientRequestToken'])
|
||||
except Exception as err:
|
||||
error_msg = boto_exception(err)
|
||||
module.fail_json(msg="Failed to create stack {0}: {1}.".format(stack_params.get('StackName'), error_msg), exception=traceback.format_exc())
|
||||
|
@ -300,6 +311,10 @@ def create_changeset(module, stack_params, cfn):
|
|||
module.fail_json(msg="Either 'template' or 'template_url' is required.")
|
||||
if module.params['changeset_name'] is not None:
|
||||
stack_params['ChangeSetName'] = module.params['changeset_name']
|
||||
|
||||
# changesets don't accept ClientRequestToken parameters
|
||||
stack_params.pop('ClientRequestToken', None)
|
||||
|
||||
try:
|
||||
changeset_name = build_changeset_name(stack_params)
|
||||
stack_params['ChangeSetName'] = changeset_name
|
||||
|
@ -336,7 +351,7 @@ def update_stack(module, stack_params, cfn):
|
|||
# don't need to be updated.
|
||||
try:
|
||||
cfn.update_stack(**stack_params)
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'UPDATE')
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'UPDATE', stack_params['ClientRequestToken'])
|
||||
except Exception as err:
|
||||
error_msg = boto_exception(err)
|
||||
if 'No updates are to be performed.' in error_msg:
|
||||
|
@ -368,7 +383,7 @@ def boto_supports_termination_protection(cfn):
|
|||
return hasattr(cfn, "update_termination_protection")
|
||||
|
||||
|
||||
def stack_operation(cfn, stack_name, operation):
|
||||
def stack_operation(cfn, stack_name, operation, op_token=None):
|
||||
'''gets the status of a stack while it is created/updated/deleted'''
|
||||
existed = []
|
||||
while True:
|
||||
|
@ -379,15 +394,15 @@ def stack_operation(cfn, stack_name, operation):
|
|||
# If the stack previously existed, and now can't be found then it's
|
||||
# been deleted successfully.
|
||||
if 'yes' in existed or operation == 'DELETE': # stacks may delete fast, look in a few ways.
|
||||
ret = get_stack_events(cfn, stack_name)
|
||||
ret = get_stack_events(cfn, stack_name, op_token)
|
||||
ret.update({'changed': True, 'output': 'Stack Deleted'})
|
||||
return ret
|
||||
else:
|
||||
return {'changed': True, 'failed': True, 'output': 'Stack Not Found', 'exception': traceback.format_exc()}
|
||||
ret = get_stack_events(cfn, stack_name)
|
||||
ret = get_stack_events(cfn, stack_name, op_token)
|
||||
if not stack:
|
||||
if 'yes' in existed or operation == 'DELETE': # stacks may delete fast, look in a few ways.
|
||||
ret = get_stack_events(cfn, stack_name)
|
||||
ret = get_stack_events(cfn, stack_name, op_token)
|
||||
ret.update({'changed': True, 'output': 'Stack Deleted'})
|
||||
return ret
|
||||
else:
|
||||
|
@ -430,6 +445,9 @@ def build_changeset_name(stack_params):
|
|||
def check_mode_changeset(module, stack_params, cfn):
|
||||
"""Create a change set, describe it and delete it before returning check mode outputs."""
|
||||
stack_params['ChangeSetName'] = build_changeset_name(stack_params)
|
||||
# changesets don't accept ClientRequestToken parameters
|
||||
stack_params.pop('ClientRequestToken', None)
|
||||
|
||||
try:
|
||||
change_set = cfn.create_change_set(**stack_params)
|
||||
for i in range(60): # total time 5 min
|
||||
|
@ -506,6 +524,7 @@ def main():
|
|||
# collect the parameters that are passed to boto3. Keeps us from having so many scalars floating around.
|
||||
stack_params = {
|
||||
'Capabilities': ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM'],
|
||||
'ClientRequestToken': to_native(uuid.uuid4()),
|
||||
}
|
||||
state = module.params['state']
|
||||
stack_params['StackName'] = module.params['stack_name']
|
||||
|
@ -610,7 +629,7 @@ def main():
|
|||
result = {'changed': False, 'output': 'Stack not found.'}
|
||||
else:
|
||||
cfn.delete_stack(StackName=stack_params['StackName'])
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'DELETE')
|
||||
result = stack_operation(cfn, stack_params['StackName'], 'DELETE', stack_params['ClientRequestToken'])
|
||||
except Exception as err:
|
||||
module.fail_json(msg=boto_exception(err), exception=traceback.format_exc())
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue