mirror of https://github.com/ansible/ansible.git
cloudformation integration tests (#65643)
parent
80f5503ed0
commit
b8729b2544
@ -0,0 +1,3 @@
|
|||||||
|
cloud/aws
|
||||||
|
shippable/aws/group2
|
||||||
|
cloudformation_info
|
@ -0,0 +1,8 @@
|
|||||||
|
stack_name: "{{ resource_prefix }}"
|
||||||
|
|
||||||
|
vpc_name: '{{ resource_prefix }}-vpc'
|
||||||
|
vpc_seed: '{{ resource_prefix }}'
|
||||||
|
vpc_cidr: '10.{{ 256 | random(seed=vpc_seed) }}.0.0/16'
|
||||||
|
subnet_cidr: '10.{{ 256 | random(seed=vpc_seed) }}.32.0/24'
|
||||||
|
|
||||||
|
ec2_ami_name: 'amzn2-ami-hvm-2.*-x86_64-gp2'
|
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||||
|
|
||||||
|
"Description" : "Create an Amazon EC2 instance.",
|
||||||
|
|
||||||
|
"Parameters" : {
|
||||||
|
"InstanceType" : {
|
||||||
|
"Description" : "EC2 instance type",
|
||||||
|
"Type" : "String",
|
||||||
|
"Default" : "t3.nano",
|
||||||
|
"AllowedValues" : [ "t3.micro", "t3.nano"]
|
||||||
|
},
|
||||||
|
"ImageId" : {
|
||||||
|
"Type" : "String"
|
||||||
|
},
|
||||||
|
"SubnetId" : {
|
||||||
|
"Type" : "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"Resources" : {
|
||||||
|
"EC2Instance" : {
|
||||||
|
"Type" : "AWS::EC2::Instance",
|
||||||
|
"Properties" : {
|
||||||
|
"InstanceType" : { "Ref" : "InstanceType" },
|
||||||
|
"ImageId" : { "Ref" : "ImageId" },
|
||||||
|
"SubnetId": { "Ref" : "SubnetId" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"Outputs" : {
|
||||||
|
"InstanceId" : {
|
||||||
|
"Value" : { "Ref" : "EC2Instance" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,365 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- module_defaults:
|
||||||
|
group/aws:
|
||||||
|
aws_access_key: '{{ aws_access_key | default(omit) }}'
|
||||||
|
aws_secret_key: '{{ aws_secret_key | default(omit) }}'
|
||||||
|
security_token: '{{ security_token | default(omit) }}'
|
||||||
|
region: '{{ aws_region | default(omit) }}'
|
||||||
|
|
||||||
|
block:
|
||||||
|
|
||||||
|
# ==== Env setup ==========================================================
|
||||||
|
|
||||||
|
- name: Create a test VPC
|
||||||
|
ec2_vpc_net:
|
||||||
|
name: "{{ vpc_name }}"
|
||||||
|
cidr_block: "{{ vpc_cidr }}"
|
||||||
|
tags:
|
||||||
|
Name: Cloudformation testing
|
||||||
|
register: testing_vpc
|
||||||
|
|
||||||
|
- name: Create a test subnet
|
||||||
|
ec2_vpc_subnet:
|
||||||
|
vpc_id: "{{ testing_vpc.vpc.id }}"
|
||||||
|
cidr: "{{ subnet_cidr }}"
|
||||||
|
register: testing_subnet
|
||||||
|
|
||||||
|
- name: Find AMI to use
|
||||||
|
ec2_ami_info:
|
||||||
|
owners: 'amazon'
|
||||||
|
filters:
|
||||||
|
name: '{{ ec2_ami_name }}'
|
||||||
|
register: ec2_amis
|
||||||
|
|
||||||
|
- name: Set fact with latest AMI
|
||||||
|
vars:
|
||||||
|
latest_ami: '{{ ec2_amis.images | sort(attribute="creation_date") | last }}'
|
||||||
|
set_fact:
|
||||||
|
ec2_ami_image: '{{ latest_ami.image_id }}'
|
||||||
|
|
||||||
|
# ==== Cloudformation tests ===============================================
|
||||||
|
|
||||||
|
# 1. Basic stack creation (check mode, actual run and idempotency)
|
||||||
|
# 2. Tags
|
||||||
|
# 3. cloudformation_info tests (basic + all_facts)
|
||||||
|
# 4. termination_protection
|
||||||
|
# 5. create_changeset + changeset_name
|
||||||
|
|
||||||
|
# There is still scope to add tests for -
|
||||||
|
# 1. capabilities
|
||||||
|
# 2. stack_policy
|
||||||
|
# 3. on_create_failure (covered in unit tests)
|
||||||
|
# 4. Passing in a role
|
||||||
|
# 5. nested stacks?
|
||||||
|
|
||||||
|
|
||||||
|
- name: create a cloudformation stack (check mode)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cf_stack.changed
|
||||||
|
- "'msg' in cf_stack and 'New stack would be created' in cf_stack.msg"
|
||||||
|
|
||||||
|
- name: create a cloudformation stack
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cf_stack.changed
|
||||||
|
- "'events' in cf_stack"
|
||||||
|
- "'output' in cf_stack and 'Stack CREATE complete' in cf_stack.output"
|
||||||
|
- "'stack_outputs' in cf_stack and 'InstanceId' in cf_stack.stack_outputs"
|
||||||
|
- "'stack_resources' in cf_stack"
|
||||||
|
|
||||||
|
- name: create a cloudformation stack (check mode) (idempotent)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not cf_stack.changed
|
||||||
|
|
||||||
|
- name: create a cloudformation stack (idempotent)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not cf_stack.changed
|
||||||
|
- "'output' in cf_stack and 'Stack is already up-to-date.' in cf_stack.output"
|
||||||
|
- "'stack_outputs' in cf_stack and 'InstanceId' in cf_stack.stack_outputs"
|
||||||
|
- "'stack_resources' in cf_stack"
|
||||||
|
|
||||||
|
- name: get stack details
|
||||||
|
cloudformation_info:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
register: stack_info
|
||||||
|
|
||||||
|
- name: assert stack info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'cloudformation' in stack_info"
|
||||||
|
- "stack_info.cloudformation | length == 1"
|
||||||
|
- "stack_name in stack_info.cloudformation"
|
||||||
|
- "'stack_description' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_outputs' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_parameters' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_tags' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "stack_info.cloudformation[stack_name].stack_tags.Stack == stack_name"
|
||||||
|
|
||||||
|
- name: get stack details (all_facts)
|
||||||
|
cloudformation_info:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
all_facts: yes
|
||||||
|
register: stack_info
|
||||||
|
|
||||||
|
- name: assert stack info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'stack_events' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_policy' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_resource_list' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_resources' in stack_info.cloudformation[stack_name]"
|
||||||
|
- "'stack_template' in stack_info.cloudformation[stack_name]"
|
||||||
|
|
||||||
|
# ==== Cloudformation tests (create changeset) ============================
|
||||||
|
|
||||||
|
# try to create a changeset by changing instance type
|
||||||
|
- name: create a changeset
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
create_changeset: yes
|
||||||
|
changeset_name: "test-changeset"
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.micro"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: create_changeset_result
|
||||||
|
|
||||||
|
- name: assert changeset created
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "create_changeset_result.changed"
|
||||||
|
- "'change_set_id' in create_changeset_result"
|
||||||
|
- "'Stack CREATE_CHANGESET complete' in create_changeset_result.output"
|
||||||
|
|
||||||
|
# try to create an empty changeset by passing in unchanged template
|
||||||
|
- name: create a changeset
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
create_changeset: yes
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: create_changeset_result
|
||||||
|
|
||||||
|
- name: assert changeset created
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "not create_changeset_result.changed"
|
||||||
|
- "'The created Change Set did not contain any changes to this stack and was deleted.' in create_changeset_result.output"
|
||||||
|
|
||||||
|
# ==== Cloudformation tests (termination_protection) ======================
|
||||||
|
|
||||||
|
- name: set termination protection to true
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
termination_protection: yes
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
# This fails - #65592
|
||||||
|
# - name: check task return attributes
|
||||||
|
# assert:
|
||||||
|
# that:
|
||||||
|
# - cf_stack.changed
|
||||||
|
|
||||||
|
- name: get stack details
|
||||||
|
cloudformation_info:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
register: stack_info
|
||||||
|
|
||||||
|
- name: assert stack info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "stack_info.cloudformation[stack_name].stack_description.enable_termination_protection"
|
||||||
|
|
||||||
|
- name: set termination protection to false
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
termination_protection: no
|
||||||
|
template_body: "{{ lookup('file','cf_template.json') }}"
|
||||||
|
template_parameters:
|
||||||
|
InstanceType: "t3.nano"
|
||||||
|
ImageId: "{{ ec2_ami_image }}"
|
||||||
|
SubnetId: "{{ testing_subnet.subnet.id }}"
|
||||||
|
tags:
|
||||||
|
Stack: "{{ stack_name }}"
|
||||||
|
test: "{{ resource_prefix }}"
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
# This fails - #65592
|
||||||
|
# - name: check task return attributes
|
||||||
|
# assert:
|
||||||
|
# that:
|
||||||
|
# - cf_stack.changed
|
||||||
|
|
||||||
|
- name: get stack details
|
||||||
|
cloudformation_info:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
register: stack_info
|
||||||
|
|
||||||
|
- name: assert stack info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "not stack_info.cloudformation[stack_name].stack_description.enable_termination_protection"
|
||||||
|
|
||||||
|
# ==== Cloudformation tests (delete stack tests) ==========================
|
||||||
|
|
||||||
|
- name: delete cloudformation stack (check mode)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
state: absent
|
||||||
|
check_mode: yes
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cf_stack.changed
|
||||||
|
- "'msg' in cf_stack and 'Stack would be deleted' in cf_stack.msg"
|
||||||
|
|
||||||
|
- name: delete cloudformation stack
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
state: absent
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- cf_stack.changed
|
||||||
|
- "'output' in cf_stack and 'Stack Deleted' in cf_stack.output"
|
||||||
|
|
||||||
|
- name: delete cloudformation stack (check mode) (idempotent)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
state: absent
|
||||||
|
check_mode: yes
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not cf_stack.changed
|
||||||
|
- "'msg' in cf_stack"
|
||||||
|
- >-
|
||||||
|
"Stack doesn't exist" in cf_stack.msg
|
||||||
|
|
||||||
|
- name: delete cloudformation stack (idempotent)
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
state: absent
|
||||||
|
register: cf_stack
|
||||||
|
|
||||||
|
- name: check task return attributes
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- not cf_stack.changed
|
||||||
|
- "'output' in cf_stack and 'Stack not found.' in cf_stack.output"
|
||||||
|
|
||||||
|
- name: get stack details
|
||||||
|
cloudformation_info:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
register: stack_info
|
||||||
|
|
||||||
|
- name: assert stack info
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "not stack_info.cloudformation"
|
||||||
|
|
||||||
|
# ==== Cleanup ============================================================
|
||||||
|
|
||||||
|
always:
|
||||||
|
|
||||||
|
- name: delete stack
|
||||||
|
cloudformation:
|
||||||
|
stack_name: "{{ stack_name }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Delete test subnet
|
||||||
|
ec2_vpc_subnet:
|
||||||
|
vpc_id: "{{ testing_vpc.vpc.id }}"
|
||||||
|
cidr: "{{ subnet_cidr }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- name: Delete test VPC
|
||||||
|
ec2_vpc_net:
|
||||||
|
name: "{{ vpc_name }}"
|
||||||
|
cidr_block: "{{ vpc_cidr }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: yes
|
Loading…
Reference in New Issue