diff --git a/changelogs/fragments/20231219-deploy_flask_app-update-arguments-spec.yml b/changelogs/fragments/20231219-deploy_flask_app-update-arguments-spec.yml index f968915e..a8f8cb62 100644 --- a/changelogs/fragments/20231219-deploy_flask_app-update-arguments-spec.yml +++ b/changelogs/fragments/20231219-deploy_flask_app-update-arguments-spec.yml @@ -3,3 +3,8 @@ breaking_changes: - >- roles/deploy_flask_app - Add parameter ``deploy_flask_app_bastion_ssh_private_key`` to define the path to the ssh private key file to use to connect to the bastion host (https://github.com/redhat-cop/cloud.aws_ops/issues/103). + - >- + roles/deploy_flask_app - The following parameters no longer required have been removed + ``deploy_flask_app_bastion_host_required_packages``, ``deploy_flask_app_local_registry_port``, + ``deploy_flask_app_local_registry_pwd``, ``deploy_flask_app_local_registry_user``, + ``deploy_flask_app_git_repository`` (https://github.com/redhat-cop/cloud.aws_ops/issues/103). diff --git a/roles/deploy_flask_app/defaults/main.yml b/roles/deploy_flask_app/defaults/main.yml index f57b9c25..5fa51023 100644 --- a/roles/deploy_flask_app/defaults/main.yml +++ b/roles/deploy_flask_app/defaults/main.yml @@ -1,2 +1,3 @@ --- -deploy_flask_app_workers_ssh_private_key: "/tmp/id_rsa" +deploy_flask_app_workers_ssh_private_key: /tmp/id_rsa +deploy_flask_app_container_image: docker.io/aubinredhat/webapp:1.0.0 diff --git a/roles/deploy_flask_app/files/run_app.yaml b/roles/deploy_flask_app/files/run_app.yaml deleted file mode 100644 index b221927b..00000000 --- a/roles/deploy_flask_app/files/run_app.yaml +++ /dev/null @@ -1,68 +0,0 @@ ---- -- name: Run app - hosts: all - gather_facts: false - strategy: free - become: true - - vars: - container_name: webapp-container01 - - tasks: - - 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 - - - name: Install Podman - ansible.builtin.yum: - name: - - podman - update_cache: True - state: present - - - name: Pull image from private registry - ansible.builtin.shell: - cmd: > - podman login {{ registry_host_port }} - -u {{ registry_login.user }} - -p {{ registry_login.password }} - --tls-verify=false && - podman pull {{ registry_host_port }}/ansible-webapp - --tls-verify=false - changed_when: false - - - name: Check running container - ansible.builtin.shell: - cmd: > - podman container ps -a - -f name={{ container_name }} - --format=.Names - register: container - changed_when: false - - - name: Run application instance - ansible.builtin.shell: - cmd: > - podman run --rm - -e FLASK_APP="{{ application_dir }}" - -e FLASK_ENV="{{ application_env }}" - -e DATABASE_HOST="{{ application_db.host }}" - -e DATABASE_INSTANCE="{{ application_db.instance }}" - -e DATABASE_USER="{{ application_db.dbuser_name }}" - -e DATABASE_PASSWORD="{{ application_db.dbuser_password }}" - -e ADMIN_USER="{{ application_db.admin_user }}" - -e ADMIN_PASSWORD="{{ application_db.admin_password }}" - -e WORKER_HOSTNAME="{{ inventory_hostname }}" - -e WORKERS_HOSTS="{{ workers_hosts }}" - -p 5000:5000 --name {{ container_name }} - -d {{ registry_host_port }}/ansible-webapp - when: - - container.stdout == "" - changed_when: true diff --git a/roles/deploy_flask_app/meta/argument_specs.yml b/roles/deploy_flask_app/meta/argument_specs.yml index 008f629e..b7d5dc9d 100644 --- a/roles/deploy_flask_app/meta/argument_specs.yml +++ b/roles/deploy_flask_app/meta/argument_specs.yml @@ -21,11 +21,6 @@ argument_specs: type: path required: True version_added: 2.1.0 - deploy_flask_app_bastion_host_required_packages: - description: Packages to be installed on the bastion host. - type: list - elements: str - required: True deploy_flask_app_private_subnet_id: description: Private subnet id of the bastion host. type: str @@ -65,10 +60,6 @@ argument_specs: description: Username for the workers. type: str required: True - deploy_flask_app_git_repository: - description: Git repository to be cloned for the webapp. - type: str - required: True deploy_flask_app_listening_port: description: Load balancer port. type: int @@ -77,18 +68,6 @@ argument_specs: description: A boolean value True to force init the app and False to not force init. type: bool required: True - deploy_flask_app_local_registry_user: - description: Registry user name. - type: str - required: True - deploy_flask_app_local_registry_pwd: - description: Registry password. - type: str - required: True - deploy_flask_app_local_registry_port: - description: Registry port. - type: int - required: True deploy_flask_app_config: description: A dict of config parameterys for the app. type: dict diff --git a/roles/deploy_flask_app/tasks/build_app.yaml b/roles/deploy_flask_app/tasks/build_app.yaml deleted file mode 100644 index cd7b77ae..00000000 --- a/roles/deploy_flask_app/tasks/build_app.yaml +++ /dev/null @@ -1,69 +0,0 @@ ---- -- name: Clone git repository for web application - ansible.builtin.git: - repo: "{{ deploy_flask_app_git_repository }}" - dest: ~/webapp - -- name: Build webapp container image - ansible.builtin.command: - cmd: podman build -t webapp . - args: - chdir: ~/webapp - changed_when: false - -- name: Check running registry - ansible.builtin.shell: - cmd: > - podman container - ps -a - -f name=registry500x - --format=.Names - register: deploy_flask_app_container - become: true - changed_when: false - -- name: Create private registry - become: true - when: - - deploy_flask_app_container.stdout == "" - block: - - name: Create folders for the registry - ansible.builtin.file: - path: /opt/registry/{{ item }} - state: directory - mode: 0644 - with_items: - - auth - - certs - - data - - - name: Generate credentials for accessing the registry - ansible.builtin.shell: - cmd: > - htpasswd -bBc /opt/registry/auth/htpasswd - {{ deploy_flask_app_local_registry_user }} - {{ deploy_flask_app_local_registry_pwd }} - changed_when: false - - - name: Start the registry - ansible.builtin.shell: - cmd: > - podman run --name registry500x - -p {{ deploy_flask_app_listening_port }}:5000 - -v /opt/registry/data:/var/lib/registry:z - -v /opt/registry/auth:/auth:z - -e "REGISTRY_AUTH=htpasswd" - -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" - -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd - -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true - -d - docker.io/library/registry:latest - changed_when: false - -- name: Push image into private registry - ansible.builtin.shell: - cmd: > - podman login 127.0.0.1:{{ deploy_flask_app_listening_port }} -u '{{ deploy_flask_app_local_registry_user }}' -p '{{ deploy_flask_app_local_registry_pwd }}' --tls-verify=false && - podman tag webapp 127.0.0.1:{{ deploy_flask_app_listening_port }}/ansible-webapp && - podman push 127.0.0.1:{{ deploy_flask_app_listening_port }}/ansible-webapp --tls-verify=false - changed_when: false diff --git a/roles/deploy_flask_app/tasks/deploy_app.yaml b/roles/deploy_flask_app/tasks/deploy_app.yaml index 058fccae..406d32f0 100644 --- a/roles/deploy_flask_app/tasks/deploy_app.yaml +++ b/roles/deploy_flask_app/tasks/deploy_app.yaml @@ -1,53 +1,54 @@ --- -- name: Generate configuration (inventory, vars) from templates - ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - mode: 0644 - with_items: - - src: inventory.j2 - dest: ~/inventory.ini - - src: vars.yaml.j2 - dest: vars.yaml +- 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: Ensure workers are reachable from bastion host - ansible.builtin.command: - cmd: "ansible -m ping -i ~/inventory.ini all" + - name: Install Podman + ansible.builtin.yum: + name: + - podman + update_cache: False + state: present + become: true -- name: Initialize database tables - 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_setup.add_host.host_vars.host_config.rds_info.host }}" - -e DATABASE_INSTANCE="{{ deploy_flask_app_setup.add_host.host_vars.host_config.rds_info.name }}" - -e DATABASE_USER="{{ deploy_flask_app_setup.add_host.host_vars.host_config.rds_info.master_username }}" - -e DATABASE_PASSWORD="{{ deploy_flask_app_setup.add_host.host_vars.host_config.rds_info.master_user_password }}" - -e ADMIN_USER="{{ deploy_flask_app_config.admin_user }}" - -e ADMIN_PASSWORD="{{ deploy_flask_app_config.admin_password }}" - -e WORKER_HOSTNAME="{{ inventory_hostname }}" - -e WORKERS_HOSTS="bastion" - webapp flask {{ deploy_flask_app_force_init | bool | ternary('force-init-db', 'init-db') }} - run_once: true - changed_when: false + - 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: Copy playbook into bastion host - ansible.builtin.copy: - src: run_app.yaml - dest: ~/playbook.yaml - mode: 0644 - -- name: Deploy application into workers - ansible.builtin.shell: - cmd: > - ansible-playbook playbook.yaml -i inventory.ini -vvv - -e '@vars.yaml' - -e registry_host_port='{{ deploy_flask_app_setup.add_host.host_vars.host_config.private_ip }}:{{ deploy_flask_app_listening_port }}' - args: - chdir: ~/ - changed_when: false - -- name: Debug application url - ansible.builtin.debug: - msg: "Application url: {{ deploy_flask_app_lb_result.elb.dns_name }}:{{ deploy_flask_app_listening_port }}" + - 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 49cc02ff..328d2a8d 100644 --- a/roles/deploy_flask_app/tasks/main.yaml +++ b/roles/deploy_flask_app/tasks/main.yaml @@ -19,14 +19,8 @@ - name: Add bastion host to inventory ansible.builtin.include_tasks: update_inventory.yaml - - name: Running from bastion host - delegate_to: bastion - block: - - name: Deploy resource from Bastion - ansible.builtin.include_tasks: setup_bastion.yaml - - - name: Build application and push container image into private registry - ansible.builtin.include_tasks: build_app.yaml - - - name: Deploy App - ansible.builtin.include_tasks: deploy_app.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 diff --git a/roles/deploy_flask_app/tasks/setup_bastion.yaml b/roles/deploy_flask_app/tasks/setup_bastion.yaml deleted file mode 100644 index eb5ec09e..00000000 --- a/roles/deploy_flask_app/tasks/setup_bastion.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -- 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 required packages - ansible.builtin.yum: - name: "{{ deploy_flask_app_bastion_host_required_packages }}" - state: present - become: true - when: deploy_flask_app_bastion_host_required_packages | length > 0 - -- name: Generate ssh configuration for current user - ansible.builtin.user: - generate_ssh_key: true - state: present - name: "{{ deploy_flask_app_bastion_host_username }}" - -- 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 diff --git a/roles/deploy_flask_app/tasks/setup_infra.yaml b/roles/deploy_flask_app/tasks/setup_infra.yaml index 7b7ed634..e366d812 100644 --- a/roles/deploy_flask_app/tasks/setup_infra.yaml +++ b/roles/deploy_flask_app/tasks/setup_infra.yaml @@ -52,17 +52,12 @@ - name: Create list of instances (join) ansible.builtin.set_fact: - deploy_flask_app_instances_list: [] + deploy_flask_app_instances: [] - name: Update join_instances ansible.builtin.set_fact: - deploy_flask_app_instances_list: "{{ deploy_flask_app_instances_list + [item.instance_id + ':' + item.private_ip_address] }}" + deploy_flask_app_instances: "{{ deploy_flask_app_instances + [item.instance_id + ':' + item.private_ip_address] }}" with_items: "{{ deploy_flask_app_vms.instances }}" - - name: Set variables - ansible.builtin.set_fact: - deploy_flask_app_workers_instances: "{{ deploy_flask_app_vms.instances }}" - deploy_flask_app_workers_join: "{{ deploy_flask_app_instances_list | join(',') }}" - - name: Create load balancer amazon.aws.elb_classic_lb: state: present diff --git a/roles/deploy_flask_app/tasks/update_inventory.yaml b/roles/deploy_flask_app/tasks/update_inventory.yaml index cc8286df..5db69292 100644 --- a/roles/deploy_flask_app/tasks/update_inventory.yaml +++ b/roles/deploy_flask_app/tasks/update_inventory.yaml @@ -1,21 +1,38 @@ --- +# 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_ssh_user: "{{ deploy_flask_app_bastion_host_username }}" - ansible_host: "{{ deploy_flask_app__bastion_public_ip }}" - ansible_ssh_common_args: -o "UserKnownHostsFile=/dev/null" -o StrictHostKeyChecking=no -i {{ deploy_flask_app_bastion_ssh_private_key }} ansible_python_interpreter: auto - ansible_host_name: "{{ deploy_flask_app__resource_prefix }}" - host_config: - public_subnet_id: "{{ deploy_flask_app__public_subnet_id }}" - private_subnet_id: "{{ deploy_flask_app__private_subnet_id }}" - image_id: "{{ deploy_flask_app__vm_image_id }}" - group_id: "{{ deploy_flask_app__group_id }}" - private_ip: "{{ deploy_flask_app__bastion_private_ip }}" - vpc_id: "{{ deploy_flask_app_vpc_id }}" - rds_info: - host: "{{ deploy_flask_app__rds_host }}" - name: "{{ deploy_flask_app__rds_dbname }}" - master_user_password: "{{ deploy_flask_app_rds_master_password }}" - master_username: "{{ deploy_flask_app_rds_master_username }}" + 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/inventory.j2 b/roles/deploy_flask_app/templates/inventory.j2 deleted file mode 100644 index 80f633bb..00000000 --- a/roles/deploy_flask_app/templates/inventory.j2 +++ /dev/null @@ -1,4 +0,0 @@ -[all] -{% for item in deploy_flask_app_workers_instances %} -{{ item.instance_id }} workers_hosts="{{ deploy_flask_app_workers_join }}" ansible_ssh_user="{{ deploy_flask_app_workers_user_name }}" ansible_ssh_common_args='-o "UserKnownHostsFile=/dev/null" -o StrictHostKeyChecking=no -i {{ deploy_flask_app_workers_ssh_private_key }}' ansible_host="{{ item.private_ip_address }}" -{% endfor %} diff --git a/roles/deploy_flask_app/templates/ssh_config.j2 b/roles/deploy_flask_app/templates/ssh_config.j2 new file mode 100644 index 00000000..28e8a98f --- /dev/null +++ b/roles/deploy_flask_app/templates/ssh_config.j2 @@ -0,0 +1,15 @@ +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/vars.yaml.j2 b/roles/deploy_flask_app/templates/vars.yaml.j2 deleted file mode 100644 index 86b3046f..00000000 --- a/roles/deploy_flask_app/templates/vars.yaml.j2 +++ /dev/null @@ -1,15 +0,0 @@ ---- -registry_host_port: "{{ deploy_flask_app_setup.add_host.host_vars.host_config.private_ip }}:{{ deploy_flask_app_local_registry_port }}" -registry_login: - user: "{{ deploy_flask_app_local_registry_user }}" - password: "{{ deploy_flask_app_local_registry_pwd }}" -rds_listening_port: "{{ rds_listening_port }}" -application_dir: "{{ deploy_flask_app_config.app_dir }}" -application_env: "{{ deploy_flask_app_config.env }}" -application_db: - host: "{{ deploy_flask_app__rds_host }}" - instance: "{{ deploy_flask_app__rds_dbname }}" - dbuser_name: "{{ deploy_flask_app_rds_master_username }}" - dbuser_password: "{{ deploy_flask_app_rds_master_password }}" - admin_user: "{{ deploy_flask_app_config.admin_user }}" - admin_password: "{{ deploy_flask_app_config.admin_password }}" 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 8f654ac0..72c0b8d2 100644 --- a/tests/integration/targets/test_deploy_flask_app/vars/main.yaml +++ b/tests/integration/targets/test_deploy_flask_app/vars/main.yaml @@ -30,31 +30,18 @@ bastion_host_iam_role: "{{ resource_prefix }}-role" deploy_flask_app_bastion_host_name: "{{ resource_prefix }}-bastion" deploy_flask_app_bastion_host_username: fedora -deploy_flask_app_bastion_host_required_packages: [] -deploy_flask_app_bastion_cloud_config_packages: - - python3 - - python-virtualenv - - sshpass - - git - - podman - - httpd-tools - - ansible deploy_flask_app_sshkey_pair_name: "{{ resource_prefix }}-key" deploy_flask_app_workers_user_name: fedora deploy_flask_app_workers_instance_type: t3.micro deploy_flask_app_number_of_workers: 2 deploy_flask_app_listening_port: 5000 -deploy_flask_app_git_repository: https://github.com/abikouo/webapp_pyflask_demo.git deploy_flask_app_config: env: development admin_user: admin admin_password: admin app_dir: /app/pyapp deploy_flask_app_force_init: false -deploy_flask_app_local_registry_user: ansible -deploy_flask_app_local_registry_pwd: testing123 -deploy_flask_app_local_registry_port: "{{ deploy_flask_app_listening_port }}" deploy_flask_app_rds_master_password: L#5cH2mgy_ deploy_flask_app_rds_master_username: ansible