diff --git a/roles/deploy_flask_app/defaults/main.yml b/roles/deploy_flask_app/defaults/main.yml index 5fa51023..b93c0b82 100644 --- a/roles/deploy_flask_app/defaults/main.yml +++ b/roles/deploy_flask_app/defaults/main.yml @@ -1,3 +1,5 @@ --- deploy_flask_app_workers_ssh_private_key: /tmp/id_rsa +deploy_flask_app_workers_inventory_file: /tmp/workers_inventory.yaml +deploy_flask_app_workers_playbook_file: /tmp/deploy_app.yaml deploy_flask_app_container_image: docker.io/aubinredhat/webapp:1.0.0 diff --git a/roles/deploy_flask_app/meta/main.yaml b/roles/deploy_flask_app/meta/main.yaml index 3bf1568b..975d38ef 100644 --- a/roles/deploy_flask_app/meta/main.yaml +++ b/roles/deploy_flask_app/meta/main.yaml @@ -1,4 +1,4 @@ --- -dependencies: - - role: cloud.aws_ops.aws_setup_credentials -allow_duplicates: true +# dependencies: +# - role: cloud.aws_ops.aws_setup_credentials +# allow_duplicates: true diff --git a/roles/deploy_flask_app/tasks/deploy_app.yaml b/roles/deploy_flask_app/tasks/deploy_app.yaml deleted file mode 100644 index 406d32f0..00000000 --- a/roles/deploy_flask_app/tasks/deploy_app.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -- name: Deploy application into worker - delegate_to: "{{ worker_id }}" - vars: - deploy_flask_app__worker_container_name: "webapp-container1" - block: - - name: Update ssh_config - ansible.builtin.lineinfile: - path: /etc/ssh/sshd_config - regex: "{{ item.regex }}" - line: "{{ item.line }}" - loop: - - regex: ^(# *)?ClientAliveInterval - line: ClientAliveInterval 1200 - - regex: ^(# *)?ClientAliveCountMax - line: ClientAliveCountMax 3 - become: true - - - name: Install Podman - ansible.builtin.yum: - name: - - podman - update_cache: False - state: present - become: true - - - name: Check running container - ansible.builtin.shell: - cmd: > - podman container ps -a - -f name={{ deploy_flask_app__worker_container_name }} - --format=.Names - register: container - changed_when: false - - - name: Run application instance - ansible.builtin.shell: - cmd: >- - podman run --rm - -e FLASK_APP="{{ deploy_flask_app_config.app_dir }}" - -e FLASK_ENV="{{ deploy_flask_app_config.env }}" - -e DATABASE_HOST="{{ deploy_flask_app__rds_host }}" - -e DATABASE_INSTANCE="{{ deploy_flask_app__rds_dbname }}" - -e DATABASE_USER="{{ deploy_flask_app_rds_master_username }}" - -e DATABASE_PASSWORD="{{deploy_flask_app_rds_master_password }}" - -e ADMIN_USER="{{ deploy_flask_app_config.admin_user }}" - -e ADMIN_PASSWORD="{{ deploy_flask_app_config.admin_password }}" - -e WORKER_HOSTNAME="{{ worker_id }}" - -e WORKERS_HOSTS="{{ deploy_flask_app_instances | join(',') }}" - -p 5000:5000 --name {{ deploy_flask_app__worker_container_name }} - -d {{ deploy_flask_app_container_image }} - when: - - container.stdout == "" - changed_when: true diff --git a/roles/deploy_flask_app/tasks/main.yaml b/roles/deploy_flask_app/tasks/main.yaml index 328d2a8d..93a2073a 100644 --- a/roles/deploy_flask_app/tasks/main.yaml +++ b/roles/deploy_flask_app/tasks/main.yaml @@ -16,11 +16,5 @@ - name: Create infrastructure - workers and load balancer ansible.builtin.include_tasks: setup_infra.yaml - - name: Add bastion host to inventory - ansible.builtin.include_tasks: update_inventory.yaml - - - name: Deploy application into workers - ansible.builtin.include_tasks: deploy_app.yaml - with_items: "{{ deploy_flask_app_vms.instances | map(attribute='instance_id') | list }}" - loop_control: - loop_var: worker_id + - name: Start application container into workers + ansible.builtin.include_tasks: start_containers.yaml diff --git a/roles/deploy_flask_app/tasks/setup_infra.yaml b/roles/deploy_flask_app/tasks/setup_infra.yaml index e366d812..388f2640 100644 --- a/roles/deploy_flask_app/tasks/setup_infra.yaml +++ b/roles/deploy_flask_app/tasks/setup_infra.yaml @@ -1,12 +1,5 @@ --- - name: Create Cloud Resources (workers, load balancer, etc) - 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: "{{ deploy_flask_app_region | default(aws_region) }}" - block: - name: Set variables ansible.builtin.set_fact: @@ -15,7 +8,9 @@ - name: List running instances amazon.aws.ec2_instance_info: filters: - tag:Name: "{{ deploy_flask_app_instance_name }}" + network-interface.subnet-id: "{{ deploy_flask_app_private_subnet_id }}" + key-name: "{{ deploy_flask_app_sshkey_pair_name }}" + image-id: "{{ deploy_flask_app__vm_image_id }}" instance-state-name: running register: deploy_flask_app_vms @@ -46,7 +41,9 @@ - name: List running instances (once again) amazon.aws.ec2_instance_info: filters: - tag:Name: "{{ deploy_flask_app_instance_name }}" + network-interface.subnet-id: "{{ deploy_flask_app_private_subnet_id }}" + key-name: "{{ deploy_flask_app_sshkey_pair_name }}" + image-id: "{{ deploy_flask_app__vm_image_id }}" instance-state-name: running register: deploy_flask_app_vms diff --git a/roles/deploy_flask_app/tasks/start_containers.yaml b/roles/deploy_flask_app/tasks/start_containers.yaml new file mode 100644 index 00000000..359885fc --- /dev/null +++ b/roles/deploy_flask_app/tasks/start_containers.yaml @@ -0,0 +1,83 @@ +--- +# Configure local ssh config +- name: Create ssh configuration files + ansible.builtin.file: + state: "{{ item.state }}" + path: "{{ item.path }}" + mode: '0755' + with_items: + - state: directory + path: "~/.ssh" + - state: touch + path: "~/.ssh/config" + +- name: Update local .ssh/config + ansible.builtin.blockinfile: + state: present + insertafter: EOF + dest: "~/.ssh/config" + content: "{{ lookup('template', 'local_ssh_config.j2') }}" + +- name: Add bastion host into inventory + ansible.builtin.add_host: + hostname: bastion + ansible_python_interpreter: auto + ansible_host_name: bastion + +- name: Update local .ssh/config + ansible.builtin.blockinfile: + state: present + insertafter: EOF + dest: "~/.ssh/config" + content: "{{ lookup('template', 'local_ssh_config.j2') }}" + +- name: Configure bastion + delegate_to: bastion + block: + - name: Create ssh configuration files + ansible.builtin.file: + state: "{{ item.state }}" + path: "{{ item.path }}" + mode: '0755' + with_items: + - state: directory + path: "~/.ssh" + - state: touch + path: "~/.ssh/config" + + - name: Update local .ssh/config + ansible.builtin.blockinfile: + state: present + insertafter: EOF + dest: "~/.ssh/config" + content: "{{ lookup('template', 'bastion_ssh_config.j2') }}" + + - name: Copy remote ssh private key file into bastion + ansible.builtin.copy: + src: "{{ deploy_flask_app_bastion_ssh_private_key }}" + dest: "{{ deploy_flask_app_workers_ssh_private_key }}" + mode: 0400 + + - name: Generate workers inventory file + ansible.builtin.copy: + content: "{{ lookup('template', 'workers_inventory.yaml.j2') }}" + dest: "{{ deploy_flask_app_workers_inventory_file }}" + mode: 0755 + + - name: Generate playbook to deploy application + ansible.builtin.copy: + content: "{{ lookup('template', 'deploy_app.yaml.j2') }}" + dest: "{{ deploy_flask_app_workers_playbook_file }}" + mode: 0755 + vars: + deploy_flask_app_instances_list: "{{ deploy_flask_app_instances | join(',') }}" + deploy_flask_app_worker_hostname: "{{ '{{' }} inventory_hostname {{ '}}' }}" + + - name: Deploy application into workers + ansible.builtin.shell: + cmd: >- + ansible-playbook + -i {{ deploy_flask_app_workers_inventory_file }} + {{ deploy_flask_app_workers_playbook_file }} + -v + changed_when: false diff --git a/roles/deploy_flask_app/tasks/update_inventory.yaml b/roles/deploy_flask_app/tasks/update_inventory.yaml deleted file mode 100644 index 5db69292..00000000 --- a/roles/deploy_flask_app/tasks/update_inventory.yaml +++ /dev/null @@ -1,38 +0,0 @@ ---- -# Configure local ssh config -- name: Create ssh configuration files - ansible.builtin.file: - state: "{{ item.state }}" - path: "{{ item.path }}" - with_items: - - state: directory - path: "~/.ssh" - - state: touch - path: "~/.ssh/config" - -- name: Update local .ssh/config - ansible.builtin.blockinfile: - state: present - insertafter: EOF - dest: "~/.ssh/config" - content: "{{ lookup('template', 'ssh_config.j2') }}" - -- name: Add bastion host into inventory - ansible.builtin.add_host: - hostname: bastion - ansible_python_interpreter: auto - ansible_host_name: bastion - -- name: Copy remote ssh private key file into bastion - ansible.builtin.copy: - src: "{{ deploy_flask_app_bastion_ssh_private_key }}" - dest: "{{ deploy_flask_app_workers_ssh_private_key }}" - mode: 0400 - delegate_to: bastion - -- name: Add workers into inventory - ansible.builtin.add_host: - hostname: "{{ item }}" - ansible_python_interpreter: auto - ansible_host_name: "{{ item }}" - with_items: "{{ deploy_flask_app_vms.instances | map(attribute='instance_id') | list }}" diff --git a/roles/deploy_flask_app/templates/bastion_ssh_config.j2 b/roles/deploy_flask_app/templates/bastion_ssh_config.j2 new file mode 100644 index 00000000..ec4c2e10 --- /dev/null +++ b/roles/deploy_flask_app/templates/bastion_ssh_config.j2 @@ -0,0 +1,8 @@ +{% for item in deploy_flask_app_vms.instances %} +Host {{ item.instance_id }} + User {{ deploy_flask_app_workers_user_name }} + HostName {{ item.private_ip_address }} + IdentityFile {{ deploy_flask_app_workers_ssh_private_key }} + StrictHostKeyChecking no + UserKnownHostsFile /dev/null +{% endfor %} \ No newline at end of file diff --git a/roles/deploy_flask_app/templates/deploy_app.yaml.j2 b/roles/deploy_flask_app/templates/deploy_app.yaml.j2 new file mode 100644 index 00000000..543890cc --- /dev/null +++ b/roles/deploy_flask_app/templates/deploy_app.yaml.j2 @@ -0,0 +1,49 @@ +--- +- name: Run app + hosts: all + gather_facts: false + strategy: free + become: true + + tasks: + - name: Update ssh_config to increase ssh session lifetime + ansible.builtin.blockinfile: + path: /etc/ssh/sshd_config + block: | + ClientAliveInterval 1200 + ClientAliveCountMax 3 + + - name: Install Podman + ansible.builtin.yum: + name: + - podman + update_cache: True + state: present + + - name: Check running container + ansible.builtin.shell: + cmd: "podman container ps -a -f name=webapp-container-1 --format=.Names" + register: container + changed_when: false + + - name: Run application instance + ansible.builtin.shell: + cmd: >- + podman run + --rm + -e FLASK_APP="{{ deploy_flask_app_config.app_dir }}" + -e FLASK_ENV="{{ deploy_flask_app_config.env }}" + -e DATABASE_HOST="{{ deploy_flask_app__rds_host }}" + -e DATABASE_INSTANCE="{{ deploy_flask_app__rds_dbname }}" + -e DATABASE_USER="{{ deploy_flask_app_rds_master_username }}" + -e DATABASE_PASSWORD="{{ deploy_flask_app_rds_master_password }}" + -e ADMIN_USER="{{ deploy_flask_app_config.admin_user }}" + -e ADMIN_PASSWORD="{{ deploy_flask_app_config.admin_password }}" + -e WORKER_HOSTNAME='{{ deploy_flask_app_worker_hostname }}' + -e WORKERS_HOSTS="{{ deploy_flask_app_instances_list }}" + -p 5000:5000 + --name webapp-container-1 + -d {{ deploy_flask_app_container_image }} + when: + - container.stdout == "" + changed_when: true \ No newline at end of file diff --git a/roles/deploy_flask_app/templates/local_ssh_config.j2 b/roles/deploy_flask_app/templates/local_ssh_config.j2 new file mode 100644 index 00000000..6395d992 --- /dev/null +++ b/roles/deploy_flask_app/templates/local_ssh_config.j2 @@ -0,0 +1,6 @@ +Host bastion + HostName {{ deploy_flask_app__bastion_public_ip }} + User {{ deploy_flask_app_bastion_host_username }} + IdentityFile {{ deploy_flask_app_bastion_ssh_private_key }} + StrictHostKeyChecking no + UserKnownHostsFile /dev/null \ No newline at end of file diff --git a/roles/deploy_flask_app/templates/ssh_config.j2 b/roles/deploy_flask_app/templates/ssh_config.j2 deleted file mode 100644 index 28e8a98f..00000000 --- a/roles/deploy_flask_app/templates/ssh_config.j2 +++ /dev/null @@ -1,15 +0,0 @@ -Host bastion - HostName {{ deploy_flask_app__bastion_public_ip }} - User {{ deploy_flask_app_bastion_host_username }} - IdentityFile {{ deploy_flask_app_bastion_ssh_private_key }} - StrictHostKeyChecking no - UserKnownHostsFile /dev/null - -{% for item in deploy_flask_app_vms.instances %} -Host {{ item.instance_id }} - User {{ deploy_flask_app_workers_user_name }} - HostName {{ item.private_ip_address }} - StrictHostKeyChecking no - UserKnownHostsFile /dev/null - ProxyCommand ssh -T -q -o 'ForwardAgent yes' bastion 'ssh-add {{ deploy_flask_app_workers_ssh_private_key }} && nc %h %p' -{% endfor %} \ No newline at end of file diff --git a/roles/deploy_flask_app/templates/workers_inventory.yaml.j2 b/roles/deploy_flask_app/templates/workers_inventory.yaml.j2 new file mode 100644 index 00000000..40219ae8 --- /dev/null +++ b/roles/deploy_flask_app/templates/workers_inventory.yaml.j2 @@ -0,0 +1,6 @@ +all: + hosts: +{% for item in deploy_flask_app_vms.instances %} + {{ item.instance_id }}: + ansible_python_interpreter: auto +{% endfor %} \ No newline at end of file diff --git a/tests/integration/targets/setup_rsa_keys/defaults/main.yml b/tests/integration/targets/setup_rsa_keys/defaults/main.yml new file mode 100644 index 00000000..7688fdce --- /dev/null +++ b/tests/integration/targets/setup_rsa_keys/defaults/main.yml @@ -0,0 +1,2 @@ +--- +setup_rsa_keys__path: "~/.ssh-{{ resource_prefix }}" diff --git a/tests/integration/targets/setup_rsa_keys/tasks/main.yml b/tests/integration/targets/setup_rsa_keys/tasks/main.yml index 1d0c94b8..23c16c8a 100644 --- a/tests/integration/targets/setup_rsa_keys/tasks/main.yml +++ b/tests/integration/targets/setup_rsa_keys/tasks/main.yml @@ -1,16 +1,25 @@ --- -- name: Create temporary directory to generate keys - ansible.builtin.tempfile: - state: directory - suffix: ssh - register: setup_rsa_keys__tmpdir - notify: 'Delete temporary RSA key directory' - -- name: Generate RSA keys - community.crypto.openssh_keypair: - path: "{{ setup_rsa_keys__tmpdir.path }}/id_rsa" - - name: Define path to private and public keys ansible.builtin.set_fact: - setup_rsa_keys__public_key_file: "{{ setup_rsa_keys__tmpdir.path }}/id_rsa.pub" - setup_rsa_keys__private_key_file: "{{ setup_rsa_keys__tmpdir.path }}/id_rsa" + setup_rsa_keys__public_key_file: "{{ setup_rsa_keys__path }}/id_rsa.pub" + setup_rsa_keys__private_key_file: "{{ setup_rsa_keys__path }}/id_rsa" + +- name: Check if ssh directory exists + ansible.builtin.stat: + path: "{{ item }}" + register: stats + with_items: + - "{{ setup_rsa_keys__public_key_file }}" + - "{{ setup_rsa_keys__private_key_file }}" + +- name: Generate RSA keys file + when: stats.results | selectattr('stat.exists', 'equalto', false) | list | length > 0 + block: + - name: Create directory to generate keys in + ansible.builtin.file: + path: "{{ setup_rsa_keys__path }}" + state: directory + + - name: Generate RSA keys + community.crypto.openssh_keypair: + path: "{{ setup_rsa_keys__path }}/id_rsa" diff --git a/tests/integration/targets/test_deploy_flask_app/aliases b/tests/integration/targets/test_deploy_flask_app/aliases index 02000abc..de2fdf2f 100644 --- a/tests/integration/targets/test_deploy_flask_app/aliases +++ b/tests/integration/targets/test_deploy_flask_app/aliases @@ -1,3 +1,3 @@ -!cloud/aws +cloud/aws role/deploy_flask_app time=35m diff --git a/tests/integration/targets/test_deploy_flask_app/defaults/main.yml b/tests/integration/targets/test_deploy_flask_app/defaults/main.yml index 67ac7d17..0e6574a5 100644 --- a/tests/integration/targets/test_deploy_flask_app/defaults/main.yml +++ b/tests/integration/targets/test_deploy_flask_app/defaults/main.yml @@ -1,3 +1 @@ aws_security_token: '{{ security_token | default(omit) }}' -aws_region: eu-west-2 -resource_prefix: "asnbible-test-user-data-20231221" \ No newline at end of file diff --git a/tests/integration/targets/test_deploy_flask_app/handlers/main.yml b/tests/integration/targets/test_deploy_flask_app/handlers/main.yml deleted file mode 100644 index bbbbd13d..00000000 --- a/tests/integration/targets/test_deploy_flask_app/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Delete temporary key pair file - ansible.builtin.file: - state: absent - path: "{{ test_deploy_flask_app__sshkey.path }}" - when: test_deploy_flask_app__sshkey is defined diff --git a/tests/integration/targets/test_deploy_flask_app/meta/main.yml b/tests/integration/targets/test_deploy_flask_app/meta/main.yml new file mode 100644 index 00000000..3d8b9c14 --- /dev/null +++ b/tests/integration/targets/test_deploy_flask_app/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: setup_rsa_keys diff --git a/tests/integration/targets/test_deploy_flask_app/tasks/create.yaml b/tests/integration/targets/test_deploy_flask_app/tasks/create.yaml index 9ff20a6a..6f898161 100644 --- a/tests/integration/targets/test_deploy_flask_app/tasks/create.yaml +++ b/tests/integration/targets/test_deploy_flask_app/tasks/create.yaml @@ -166,17 +166,10 @@ db_instance_identifier: "{{ rds_identifier }}" register: rds_result - - name: Create temporary file for ssh private key - ansible.builtin.tempfile: - suffix: .id_rsa - register: test_deploy_flask_app__sshkey - # notify: 'Delete temporary key pair file' - - name: Create key pair to connect to the VM amazon.aws.ec2_key: name: "{{ deploy_flask_app_sshkey_pair_name }}" - file_name: "{{ test_deploy_flask_app__sshkey.path }}" - register: rsa_key + key_material: "{{ lookup('file', setup_rsa_keys__public_key_file) }}" - name: Ensure IAM instance role exists amazon.aws.iam_role: @@ -204,7 +197,7 @@ - "{{ secgroup.group_id }}" user_data: | #!/bin/bash - yum install -y python3 python-virtualenv sshpass netcat + yum install -y python3 python-virtualenv sshpass netcat ansible wait: true state: started register: vm_result diff --git a/tests/integration/targets/test_deploy_flask_app/tasks/main.yaml b/tests/integration/targets/test_deploy_flask_app/tasks/main.yaml index 06be0a38..bc6f35b9 100644 --- a/tests/integration/targets/test_deploy_flask_app/tasks/main.yaml +++ b/tests/integration/targets/test_deploy_flask_app/tasks/main.yaml @@ -2,12 +2,10 @@ - name: "Run deploy_flask_app integration tests" module_defaults: group/aws: - # aws_access_key: "{{ aws_access_key }}" - # aws_secret_key: "{{ aws_secret_key }}" - # security_token: "{{ aws_security_token }}" - # region: "{{ aws_region }}" - aws_profile: eu_london - region: eu-west-2 + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ aws_security_token }}" + region: "{{ aws_region }}" block: - name: Run operation create @@ -21,8 +19,7 @@ deploy_flask_app_vpc_id: "{{ vpc.vpc.id }}" deploy_flask_app_vm_info: "{{ vm_result }}" deploy_flask_app_rds_info: "{{ rds_result }}" - # deploy_flask_app_bastion_ssh_private_key: "{{ test_deploy_flask_app__sshkey.path }}" - deploy_flask_app_bastion_ssh_private_key: /tmp/ansible.db0gt4_6.id_rsa + deploy_flask_app_bastion_ssh_private_key: "{{ setup_rsa_keys__private_key_file }}" - name: Check that a page returns successfully ansible.builtin.uri: @@ -32,7 +29,7 @@ retries: 5 delay: 10 - # always: - # # Cleanup after ourselves - # - name: Cleanup - # ansible.builtin.include_tasks: "delete.yaml" + always: + # Cleanup after ourselves + - name: Cleanup + ansible.builtin.include_tasks: "delete.yaml" diff --git a/tests/integration/targets/test_deploy_flask_app/vars/main.yaml b/tests/integration/targets/test_deploy_flask_app/vars/main.yaml index 72c0b8d2..69c8a0db 100644 --- a/tests/integration/targets/test_deploy_flask_app/vars/main.yaml +++ b/tests/integration/targets/test_deploy_flask_app/vars/main.yaml @@ -22,7 +22,7 @@ rds_engine: postgres rds_engine_version: "14.8" bastion_host_type: t3.micro bastion_host_venv_path: ~/env -image_filter: Fedora-Cloud-Base-37-* +image_filter: Fedora-Cloud-Base-38-* bastion_host_iam_role: "{{ resource_prefix }}-role" # vars for the deploy_flask_app role and create task