diff --git a/test/integration/Makefile b/test/integration/Makefile index da2758c1406..8d01ae2a4a9 100644 --- a/test/integration/Makefile +++ b/test/integration/Makefile @@ -48,7 +48,7 @@ $(CREDENTIALS_FILE): @exit 1 amazon: $(CREDENTIALS_FILE) - ansible-playbook amazon.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -e "resource_prefix=$(CLOUD_RESOURCE_PREFIX)" -v $(TEST_FLAGS) ; \ + BOTO_CONFIG=/dev/null ansible-playbook amazon.yml -i $(INVENTORY) -e @$(VARS_FILE) $(CREDENTIALS_ARG) -e "resource_prefix=$(CLOUD_RESOURCE_PREFIX)" -v $(TEST_FLAGS) ; \ RC=$$? ; \ CLOUD_RESOURCE_PREFIX="$(CLOUD_RESOURCE_PREFIX)" make amazon_cleanup ; \ exit $$RC; diff --git a/test/integration/cleanup_ec2.py b/test/integration/cleanup_ec2.py index d82dc4f340b..cb724a77770 100644 --- a/test/integration/cleanup_ec2.py +++ b/test/integration/cleanup_ec2.py @@ -10,6 +10,7 @@ import sys import boto import optparse import yaml +import os.path def delete_aws_resources(get_func, attr, opts): for item in get_func(): @@ -17,13 +18,36 @@ def delete_aws_resources(get_func, attr, opts): if re.search(opts.match_re, val): prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes) +def delete_aws_eips(get_func, attr, opts): + + # the file might not be there if the integration test wasn't run + try: + eip_log = open(opts.eip_log, 'r').read().splitlines() + except IOError: + print opts.eip_log, 'not found.' + return + + for item in get_func(): + val = getattr(item, attr) + if val in eip_log: + prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes) + +def delete_aws_instances(reservation, opts): + for list in reservation: + for item in list.instances: + prompt_and_delete(item, "Delete matching %s? [y/n]: " % (item,), opts.assumeyes) + def prompt_and_delete(item, prompt, assumeyes): if not assumeyes: assumeyes = raw_input(prompt).lower() == 'y' - assert hasattr(item, 'delete'), "Class <%s> has no delete attribute" % item.__class__ + assert hasattr(item, 'delete') or hasattr(item, 'terminate') , "Class <%s> has no delete or terminate attribute" % item.__class__ if assumeyes: - item.delete() - print ("Deleted %s" % item) + if hasattr(item, 'delete'): + item.delete() + print ("Deleted %s" % item) + if hasattr(item, 'terminate'): + item.terminate() + print ("Terminated %s" % item) def parse_args(): # Load details from credentials.yml @@ -47,6 +71,14 @@ def parse_args(): action="store", dest="ec2_secret_key", default=default_aws_secret_key, help="Amazon ec2 secret key. Can use EC2_SECRET_KEY environment variable, or a values from credentials.yml.") + parser.add_option("--eip-log", + action="store", dest="eip_log", + default = None, + help = "Path to log of EIPs created during test.") + parser.add_option("--integration-config", + action="store", dest="int_config", + default = "integration_config.yml", + help = "path to integration config") parser.add_option("--credentials", "-c", action="store", dest="credential_file", default="credentials.yml", @@ -65,12 +97,18 @@ def parse_args(): if getattr(opts, required) is None: parser.error("Missing required parameter: --%s" % required) + return (opts, args) if __name__ == '__main__': (opts, args) = parse_args() + int_config = yaml.load(open(opts.int_config).read()) + if not opts.eip_log: + output_dir = os.path.expanduser(int_config["output_dir"]) + opts.eip_log = output_dir + '/' + opts.match_re.replace('^','') + '-eip_integration_tests.log' + # Connect to AWS aws = boto.connect_ec2(aws_access_key_id=opts.ec2_access_key, aws_secret_access_key=opts.ec2_secret_key) @@ -81,5 +119,13 @@ if __name__ == '__main__': # Delete matching groups delete_aws_resources(aws.get_all_security_groups, 'name', opts) + + # Delete recorded EIPs + delete_aws_eips(aws.get_all_addresses, 'public_ip', opts) + + # Delete temporary instances + filters = {"tag:Name":opts.match_re.replace('^',''), "instance-state-name": ['running', 'pending', 'stopped' ]} + delete_aws_instances(aws.get_all_instances(filters=filters), opts) + except KeyboardInterrupt, e: print "\nExiting on user command." diff --git a/test/integration/roles/test_ec2_eip/defaults/main.yml b/test/integration/roles/test_ec2_eip/defaults/main.yml index 0fdf99bb9c2..76164523d46 100644 --- a/test/integration/roles/test_ec2_eip/defaults/main.yml +++ b/test/integration/roles/test_ec2_eip/defaults/main.yml @@ -1,2 +1,3 @@ --- # defaults file for test_ec2_eip +tag_prefix: '{{resource_prefix}}' diff --git a/test/integration/roles/test_ec2_eip/tasks/main.yml b/test/integration/roles/test_ec2_eip/tasks/main.yml index 6d8b49e4fc5..0223fe74bd8 100644 --- a/test/integration/roles/test_ec2_eip/tasks/main.yml +++ b/test/integration/roles/test_ec2_eip/tasks/main.yml @@ -1,2 +1,441 @@ --- -# tasks file for test_ec2_eip +# __Test Info__ +# EIPs are a scarce resource. AWS only assigns 5 per account +# by default. This test tries to only use 1 at a time. +# one t1.micro instance will also be provisioned. +# tests require setting of variables eip_ec2_keyname and +# eip_ec2_image . + +# __Test Outline__ +# +# __ec2_eip__ +# create test instance +# create EIP +# assign allocated ip to instance_id +# disassociate EIP associated with instance +# re-use existing EIP with instance +# deactivate EIP +# provision EIP with instance_id +# create VPC EIP +# re-use exiting VPC EIP with instance + +# __ec2-common__ +# test environment variable EC2_REGION +# deactivate EIP +# test with no parameters +# test with only instance_id +# test invalid region parameter +# test valid region parameter +# test invalid ec2_url parameter +# test valid ec2_url parameter +# test credentials from environment +# test credential parameters + +# ============================================================ + +# create test instance + + +- name: create test instance + local_action: + module: ec2 + key_name: "{{ eip_ec2_keyname }}" + region: "{{ ec2_region }}" + instance_type: t1.micro + image: "{{ eip_ec2_image }}" + wait: yes + instance_tags: + Name: "{{ tag_prefix }}" + ansible_ec2_eip_integration_test: foo + exact_count: 1 + count_tag: "ansible_ec2_eip_integration_test" + ec2_access_key: "{{ ec2_access_key }}" + ec2_secret_key: "{{ ec2_secret_key }}" + register: output + + +- name: set instance id fact + set_fact: instance_id={{ output.instances[0].id }} + +# eip allocated:0 assigned:0 + +# ============================================================ + +# create EIP + +- name: create EIP + ec2_eip: region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + register: result + +- name: set eip fact + set_fact: eip={{ result.public_ip }} + +- name: write ip to list for cleanup script + shell: echo {{ eip }} >> {{ output_dir }}/{{ tag_prefix }}-eip_integration_tests.log + +- name: assert EIP created + assert: + that: + - '"failed" not in result' + + +# eip allocated:1 assigned:0 + +# ============================================================ + +# assign allocated ip to instance_id + +- name: assign allocated ip to instance_id + ec2_eip: + reuse_existing_ip_allowed=yes + instance_id={{ instance_id }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + public_ip={{ eip }} + region={{ ec2_region }} + register: result + +- name: assert new EIP was assigned + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + +# eip allocated:1 assigned:1 + +# ============================================================ + +# disassociate EIP associated with instance + +- name: disassociate EIP associated with instance + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + instance_id={{ instance_id }} + register: result + +- name: assert success disassociate EIP associated with instance + assert: + that: + - '"failed" not in result' + +# eip allocated:1 assigned:0 + + +# ============================================================ + +# re-use existing EIP with instance + +- name: re-use existing EIP with instance + ec2_eip: + reuse_existing_ip_allowed=yes + instance_id={{ instance_id }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + region={{ ec2_region }} + register: result + +- name: assert new EIP was assigned + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + + +- name: disassociate EIP associated with instance + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + instance_id={{ instance_id }} + + +# eip allocated:1 assigned:1 + +# ============================================================ + +# deactivate EIP + +- name: deactivate EIP + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + register: result + +- name: assert EIP deactivated + assert: + that: + - '"failed" not in result' + + +# eip allocated:0 assigned:0 + +# ============================================================ + +# provision EIP with instance_id + +- name: provision EIP with instance_id + ec2_eip: + instance_id={{ instance_id }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + region={{ ec2_region }} + register: result + +- name: set eip fact + set_fact: eip={{ result.public_ip }} + +- name: write ip to list for cleanup script + shell: echo {{ eip }} >> {{ output_dir }}/{{ tag_prefix }}-eip_integration_tests.log + +- name: assert provision EIP with instance_id + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + +- name: disassociate EIP associated with instance + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + instance_id={{ instance_id }} + + +- name: deactivate EIP + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + + +# eip allocated:0 assigned:0 + +# ============================================================ + + +# create VPC EIP + + +- name: create VPC EIP + ec2_eip: in_vpc=yes region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + register: result + +- name: set eip fact + set_fact: eip={{ result.public_ip }} + +- name: write ip to list for cleanup script + shell: echo {{ eip }} >> {{ output_dir }}/{{ tag_prefix }}-eip_integration_tests.log + +- name: assert VPC EIP creation + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + +# eip allocated:1 assigned:0 + +# ============================================================ + +# re-use existing VPC EIP with instance + +- name: re-use existing EIP with instance + ec2_eip: + in_vpc=yes + reuse_existing_ip_allowed=yes + instance_id={{ instance_id }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + region={{ ec2_region }} + register: result + +- name: assert new EIP was assigned + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + +- name: disassociate EIP associated with instance + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + instance_id={{ instance_id }} + + +- name: deactivate EIP + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + + +# eip allocated:0 assigned:0 + + +# ============================================================ +- name: test environment variable EC2_REGION + ec2_eip: + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + environment: + EC2_REGION: "{{ ec2_region }}" + register: result + +- name: set eip fact + set_fact: eip={{ result.public_ip }} + +- name: write ip to list for cleanup script + shell: echo {{ eip }} >> {{ output_dir }}/{{ tag_prefix }}-eip_integration_tests.log + + +- name: assert environment variable EC2_REGION + assert: + that: + - '"failed" not in result' + - '"public_ip" in result' + + +- name: deactivate EIP + ec2_eip: state=absent public_ip={{ eip }} region={{ ec2_region }} + ec2_access_key={{ ec2_access_key }} + ec2_secret_key={{ ec2_secret_key }} + + +# eip allocated:0 assigned:0 + +# ============================================================ + +- name: test with no parameters + ec2_eip: + register: result + ignore_errors: true + +- name: assert failure when called with no parameters + assert: + that: + - 'result.failed' + - 'result.msg == "Either region or ec2_url must be specified"' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test with only instance_id + ec2_eip: + instance_id=i-12345 + register: result + ignore_errors: true + +- name: assert failure when called with only 'instance_id' + assert: + that: + - 'result.failed' + - 'result.msg == "Either region or ec2_url must be specified"' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test invalid region parameter + ec2_eip: + instance_id={{ instance_id }} + region='asdf querty 1234' + register: result + ignore_errors: true + +- name: assert invalid region parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("value of region must be one of:")' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test valid region parameter + ec2_eip: + instance_id={{ instance_id }} + region={{ ec2_region }} + register: result + ignore_errors: true + +- name: assert valid region parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# eip allocated:0 assigned:0 + +# ============================================================ + +- name: test invalid ec2_url parameter + ec2_eip: + instance_id={{ instance_id }} + reuse_existing_ip_allowed=yes + environment: + EC2_URL: bogus.example.com + register: result + ignore_errors: true + +- name: assert invalid ec2_url parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test valid ec2_url parameter + ec2_eip: + instance_id={{ instance_id }} + reuse_existing_ip_allowed=yes + environment: + EC2_URL: '{{ec2_url}}' + register: result + ignore_errors: true + +- name: assert valid ec2_url parameter + assert: + that: + - 'result.failed' + - 'result.msg.startswith("No handler was ready to authenticate.")' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test credentials from environment + ec2_eip: + region={{ ec2_region }} + instance_id={{ instance_id }} + environment: + EC2_ACCESS_KEY: bogus_access_key + EC2_SECRET_KEY: bogus_secret_key + register: result + ignore_errors: true + +- name: assert credentials from environment + assert: + that: + - 'result.failed' + - '"EC2ResponseError: 401 Unauthorized" in result.msg' + +# eip allocated:0 assigned:0 + +# ============================================================ +- name: test credential parameters + ec2_eip: region={{ ec2_region }} + register: result + ignore_errors: true + +- name: assert credential parameters + assert: + that: + - 'result.failed' + - '"Check your credentials" in result.msg' + +# eip allocated:0 assigned:0