cloudformation_facts: don't fail on nonexistent stack - fixes #23419 (#23758)

* Allow cloudformation_facts to exit gracefully if stack does not exist

make cloudformation_facts pep8

remove from legacy files

remove unnecessary if statement

Allow cloudformation_facts to exit gracefully if stack does not exist version 2

fix documentation errors

add an example for a hard-fail if a stack doesn't exist

* Remove extra whitespace

* Use the .response attribute since .message isn't present with Python 3

* Don't fail if no stack name is provided and no stacks exist.
This commit is contained in:
Sloane Hertel 2017-10-26 15:18:31 -04:00 committed by Ryan Brown
parent 6a6ea663ea
commit c714da7fac
2 changed files with 26 additions and 14 deletions

View file

@ -91,6 +91,13 @@ EXAMPLES = '''
stack_resources: true
stack_policy: true
# Fail if the stack doesn't exist
- name: try to get facts about a stack but fail if it doesn't exist
cloudformation_facts:
stack_name: nonexistent-stack
all_facts: yes
failed_when: cloudformation['nonexistent-stack'] is undefined
# Example dictionary outputs for stack_outputs, stack_parameters and stack_resources:
# "stack_outputs": {
# "ApplicationDatabaseName": "dazvlpr01xj55a.ap-southeast-2.rds.amazonaws.com",
@ -113,38 +120,38 @@ EXAMPLES = '''
RETURN = '''
stack_description:
description: Summary facts about the stack
returned: always
returned: if the stack exists
type: dict
stack_outputs:
description: Dictionary of stack outputs keyed by the value of each output 'OutputKey' parameter and corresponding value of each
output 'OutputValue' parameter
returned: always
returned: if the stack exists
type: dict
stack_parameters:
description: Dictionary of stack parameters keyed by the value of each parameter 'ParameterKey' parameter and corresponding value of
each parameter 'ParameterValue' parameter
returned: always
returned: if the stack exists
type: dict
stack_events:
description: All stack events for the stack
returned: only if all_facts or stack_events is true
returned: only if all_facts or stack_events is true and the stack exists
type: list
stack_policy:
description: Describes the stack policy for the stack
returned: only if all_facts or stack_policy is true
returned: only if all_facts or stack_policy is true and the stack exists
type: dict
stack_template:
description: Describes the stack template for the stack
returned: only if all_facts or stack_template is true
returned: only if all_facts or stack_template is true and the stack exists
type: dict
stack_resource_list:
description: Describes stack resources for the stack
returned: only if all_facts or stack_resourses is true
returned: only if all_facts or stack_resourses is true and the stack exists
type: list
stack_resources:
description: Dictionary of stack resources keyed by the value of each resource 'LogicalResourceId' parameter and corresponding value of each
resource 'PhysicalResourceId' parameter
returned: only if all_facts or stack_resourses is true
returned: only if all_facts or stack_resourses is true and the stack exists
type: dict
'''
@ -159,6 +166,7 @@ try:
except ImportError:
HAS_BOTO3 = False
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import (get_aws_connection_info, ec2_argument_spec, boto3_conn,
camel_dict_to_snake_dict, AWSRetry, boto3_tag_list_to_ansible_dict)
@ -191,22 +199,25 @@ class CloudFormationServiceManager:
kwargs = {'StackName': stack_name} if stack_name else {}
func = partial(self.client.describe_stacks, **kwargs)
response = self.paginated_response(func, 'Stacks')
if response:
if response is not None:
return response
self.module.fail_json(msg="Error describing stack(s) - an empty response was returned")
except Exception as e:
self.module.fail_json(msg="Error describing stack(s) - " + str(e), exception=traceback.format_exc())
if 'does not exist' in e.response['Error']['Message']:
# missing stack, don't bail.
return {}
self.module.fail_json(msg="Error describing stack - " + to_native(e), exception=traceback.format_exc())
def list_stack_resources(self, stack_name):
try:
func = partial(self.client.list_stack_resources,StackName=stack_name)
func = partial(self.client.list_stack_resources, StackName=stack_name)
return self.paginated_response(func, 'StackResourceSummaries')
except Exception as e:
self.module.fail_json(msg="Error listing stack resources - " + str(e), exception=traceback.format_exc())
def describe_stack_events(self, stack_name):
try:
func = partial(self.client.describe_stack_events,StackName=stack_name)
func = partial(self.client.describe_stack_events, StackName=stack_name)
return self.paginated_response(func, 'StackEvents')
except Exception as e:
self.module.fail_json(msg="Error describing stack events - " + str(e), exception=traceback.format_exc())
@ -233,7 +244,7 @@ class CloudFormationServiceManager:
Returns expanded response for paginated operations.
The 'result_key' is used to define the concatenated results that are combined from each paginated response.
'''
args=dict()
args = dict()
if next_token:
args['NextToken'] = next_token
response = func(**args)
@ -243,6 +254,7 @@ class CloudFormationServiceManager:
return result
return result + self.paginated_response(func, result_key, next_token)
def to_dict(items, key, value):
''' Transforms a list of items to a Key/Value dictionary '''
if items:
@ -250,6 +262,7 @@ def to_dict(items, key, value):
else:
return dict()
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(dict(

View file

@ -12,7 +12,6 @@ lib/ansible/modules/cloud/openstack/_os_server_actions.py
lib/ansible/modules/cloud/ovirt/_ovirt_affinity_groups.py
lib/ansible/modules/cloud/amazon/aws_kms.py
lib/ansible/modules/cloud/amazon/cloudformation.py
lib/ansible/modules/cloud/amazon/cloudformation_facts.py
lib/ansible/modules/cloud/amazon/cloudfront_facts.py
lib/ansible/modules/cloud/amazon/dynamodb_table.py
lib/ansible/modules/cloud/amazon/ec2_ami_copy.py