--- - name: Step 001 Deploy Infrastructure hosts: localhost connection: local gather_facts: false become: false vars_files: - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_vars.yml" - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_secret_vars.yml" tags: - step001 - deploy_infrastructure tasks: - name: AWS Generate CloudFormation Template template: src: "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/files/cloud_providers/{{cloud_provider}}_cloud_template.j2" dest: "{{ANSIBLE_REPO_PATH}}/workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template-orig" tags: - aws_infrastructure_deployment - gen_cf_template # for SSH first access to ec2 instances we always use the key defined in the CloudFormation # template by the name {{key_name}} # This variable is used when generation ssh config. - name: Get ssh pub key set_fact: ssh_key: "~/.ssh/{{key_name}}.pem" ######################### Minimize template (avoid size limitation as much as possible) - name: minimize json shell: "jq -c . < ../workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template-orig > ../workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template" register: jq_minify ignore_errors: true tags: - aws_infrastructure_deployment - gen_cf_template - minify_template - name: use original if jq failed command: "cp ../workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template-orig ../workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template" when: jq_minify is failed tags: - aws_infrastructure_deployment - gen_cf_template - minify_template ######################### Validate CF Template - name: validate cloudformation template environment: AWS_ACCESS_KEY_ID: "{{aws_access_key_id}}" AWS_SECRET_ACCESS_KEY: "{{aws_secret_access_key}}" AWS_DEFAULT_REGION: "{{aws_region}}" shell: "aws cloudformation validate-template --region {{ aws_region | default(region) | default('us-east-1')}} --template-body file://../workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template" changed_when: false tags: - aws_infrastructure_deployment - validate_cf_template ######################### Launch CF Template - name: Launch CloudFormation template # environment: # AWS_ACCESS_KEY_ID: "{{aws_access_key_id}}" # AWS_SECRET_ACCESS_KEY: "{{aws_secret_access_key}}" # AWS_DEFAULT_REGION: "{{aws_region}}" cloudformation: aws_access_key: "{{ aws_access_key_id }}" aws_secret_key: "{{ aws_secret_access_key }}" stack_name: "{{ project_tag }}" state: "present" region: "{{ aws_region | default(region) | default('us-east-1')}}" disable_rollback: true template: "{{ANSIBLE_REPO_PATH}}/workdir/{{ env_type }}.{{ guid }}.{{cloud_provider}}_cloud_template" tags: Stack: "project {{ project_tag }}" owner: "{{ email | default('unknown') }}" tags: - aws_infrastructure_deployment - provision_cf_template register: cloudformation_out until: - cloudformation_out|succeeded - cloudformation_out.output in ["Stack CREATE complete", "Stack is already up-to-date."] retries: "{{ cloudformation_retries | default(25) }}" delay: 60 ignore_errors: yes - name: debug cloudformation debug: var: cloudformation_out tags: provision_cf_template when: not cloudformation_out|succeeded - name: report Cloudformation error fail: msg: "FAIL {{ project_tag }} Create Cloudformation" when: not cloudformation_out|succeeded tags: - provision_cf_template - name: debug cloudformation debug: var: cloudformation_out verbosity: 2 tags: provision_cf_template - name: Gather EC2 facts ec2_remote_facts: aws_access_key: "{{ aws_access_key_id }}" aws_secret_key: "{{ aws_secret_access_key }}" region: "{{ aws_region | default(region) | default('us-east-1')}}" filters: instance-state-name: running "tag:Project": "{{project_tag}}" register: ec2_facts tags: - create_inventory - must - name: debug ec2_facts debug: var: ec2_facts verbosity: 2 - name: windows ostype workaround set_fact: project_tag_ostype: "{{project_tag}}_ostype" tags: - create_inventory - must - set_fact: stack_tag: "{{env_type | replace('-', '_')}}_{{guid}}" tags: - create_inventory - must - add_host: name: "{{item.tags.internaldns | default(item.private_dns_name)}}" shortname: "{{item.tags.Name | default(item.private_dns_name)}}" groups: - "tag_Project_{{stack_tag}}" - "tag_{{stack_tag}}_{{item['tags'][project_tag] | default('unknowns')}}" - "tag_{{stack_tag}}_ostype_{{item['tags'][project_tag_ostype] | default('unknown')}}" - "{{item.tags.ostype | default('unknowns')}}" - "{{item['tags'][project_tag_ostype] | default('unknowns')}}" - "{{ 'newnodes' if (item.tags.newnode|d()|bool) else 'all'}}" ansible_ssh_user: ec2-user remote_user: ec2-user ansible_ssh_private_key_file: "{{item['key_name']}}" key_name: "{{item['key_name']}}" state: "{{item['state']}}" internaldns: "{{item.tags.internaldns | default(item.private_dns_name)}}" instance_id: "{{ item.id }}" region: "{{item['region']}}" public_dns_name: "{{item['public_dns_name']}}" private_dns_name: "{{item['private_dns_name']}}" private_ip_address: "{{item['private_ip_address']}}" public_ip_address: "{{item['public_ip_address']}}" placement: "{{item['placement']['zone']}}" image_id: "{{item['image_id']}}" ansible_ssh_extra_args: "-o StrictHostKeyChecking=no" with_items: "{{ec2_facts['instances']}}" loop_control: label: "{{item.tags.internaldns | default(item.private_dns_name)}}" tags: - create_inventory - must # AnsibleGroup tag can have several comma-separated values. Ex: activedirectories,windows - add_host: name: "{{item.tags.internaldns | default(item.private_dns_name)}}" groups: "{{item.tags.AnsibleGroup}}" with_items: "{{ec2_facts['instances']}}" loop_control: label: "{{item.tags.internaldns | default(item.private_dns_name)}}" tags: - create_inventory - must - name: debug hostvars debug: var: hostvars verbosity: 2 - name: debug groups debug: var: groups verbosity: 2 - name: Configure local ssh config for bastion proxy use include: "{{ANSIBLE_REPO_PATH}}/cloud_providers/{{cloud_provider}}_ssh_config_setup.yml" when: groups['bastions'] - name: wait_for_connection for all non-windows machines and set hostname hosts: - all:!windows:!network vars_files: - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_vars.yml" - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_secret_vars.yml" gather_facts: false any_errors_fatal: true ignore_errors: false become: true tags: - step001 - wait_ssh - set_hostname tasks: - name: wait for linux host to be available wait_for_connection: timeout: 300 register: rwait ignore_errors: true - name: restart instance if wait_for_connection failed become: false environment: AWS_ACCESS_KEY_ID: "{{aws_access_key_id}}" AWS_SECRET_ACCESS_KEY: "{{aws_secret_access_key}}" AWS_DEFAULT_REGION: "{{aws_region}}" command: "aws ec2 reboot-instances --instance-ids '{{instance_id}}'" delegate_to: localhost when: rwait|failed - name: wait for linux host to be available (retry) wait_for_connection: when: rwait|failed - ping: register: rping retries: 3 delay: 10 until: rping | succeeded - name: Set hostname based on tag_internaldns hostname: name: "{{internaldns}}" when: internaldns is defined - stat: path: /etc/cloud/cloud.cfg register: cloud_cfg_file - name: disable updating hostname in /etc/cloud/cloud.cfg lineinfile: dest: /etc/cloud/cloud.cfg regexp: 'update_hostname$' line: '# - update_hostname' backup: yes when: cloud_cfg_file.stat.exists tags: disable_cloud_cfg_hostname - name: Set facts for Windows hosts if any exist and wait_for_connection gather_facts: false hosts: - windows vars_files: - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_vars.yml" - "{{ANSIBLE_REPO_PATH}}/configs/{{ env_type }}/env_secret_vars.yml" tasks: - name: set facts for remote access set_fact: ansible_become: false ansible_connection: winrm ansible_host: "{{ public_dns_name }}" ansible_password: "{{ windows_password | default(hostvars['localhost'].generated_windows_password) }}" ansible_port: 5986 ansible_user: Administrator ansible_ssh_user: Administrator ansible_winrm_server_cert_validation: ignore - name: wait for windows host to be available wait_for_connection: timeout: 900 connect_timeout: 60 delay: 120 register: rwait ignore_errors: true - name: restart instance if wait_for_connection failed become: false environment: AWS_ACCESS_KEY_ID: "{{aws_access_key_id}}" AWS_SECRET_ACCESS_KEY: "{{aws_secret_access_key}}" AWS_DEFAULT_REGION: "{{aws_region}}" command: "aws ec2 reboot-instances --instance-ids '{{instance_id}}'" delegate_to: localhost when: rwait|failed - name: wait for windows host to be available (retry) wait_for_connection: timeout: 900 connect_timeout: 60 delay: 120 when: rwait|failed