.. _2.2-error-handling: Exercise 2.2: Using a combination of modules to perform a graceful rollback ########################################################################### Objective ========= Demonstrate use of the different modules to perform a rollback of the configuration on the BIG-IP. Guide ===== Step 1 ------ Use VS Code Explorer to create a new file called ``bigip-error-handling.yml``. .. The Ansible node is equiped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. Step 2 ------ Enter the following play definition into ``bigip-error-handling.yml``: .. code-block:: yaml --- - name: BIG-IP SETUP hosts: lb connection: local gather_facts: false - The ``---`` at the top of the file indicates that this is a YAML file. - The ``hosts: f5``, indicates the play is run only on the F5 BIG-IP device - ``connection: local`` tells the Playbook to run locally (rather than SSHing to itself) - ``gather_facts: false`` disables facts gathering. We are not using any fact variables for this playbook. Step 3 ------ Add a tasks section with a set_fact for setting the provider values .. code-block:: yaml tasks: - name: Setup provider set_fact: provider: server: "{{private_ip}}" user: "{{ansible_user}}" password: "{{ansible_ssh_pass}}" server_port: "8443" validate_certs: "no" Step 4 ------ Next, add the ``block`` stanza and the first ``task``. The first task will be the bigip_node as performed in :ref:`Exercise 1.2 - Adding nodes to F5 BIG-IP <1.2-add-node>`. .. code-block:: yaml - name: Setup and graceful rollback BIG-IP configuration block: - name: CREATE NODES bigip_node: provider: "{{provider}}" host: "{{hostvars[item].ansible_host}}" name: "{{hostvars[item].inventory_hostname}}" loop: "{{ groups['webservers'] }}" Step 5 ------ Next, add the second task for bigip_pool as demonstrated in :ref:`Exercise 1.3 - Adding a load balancing pool <1.3-add-pool>`. .. code-block:: yaml - name: CREATE POOL bigip_pool: provider: "{{provider}}" name: "http_pool" lb_method: "round-robin" monitors: "/Common/http" monitor_type: "and_list" Step 6 ------ Next, add the third task. For the third task use the bigip_pool_member as demonstrated in :ref:`Exercise 1.4 - Adding members to a pool<1.4-add-pool-members>`. .. code-block:: yaml - name: ADD POOL MEMBERS bigip_pool_member: provider: "{{provider}}" state: "present" name: "{{hostvars[item].inventory_hostname}}" host: "{{hostvars[item].ansible_host}}" port: "80" pool: "http_pool" loop: "{{ groups['webservers'] }}" Step 7 ------ Next, add the fourth task. For the fourth task use the bigip_virtual_server as demonstrated in :ref:`Exercise 1.5 - Adding a virtual server<1.5-add-virtual-server>`. .. code-block:: yaml - name: ADD VIRTUAL SERVER bigip_virtual_server: provider: "{{provider}}" name: "vip" destination: "{{private_ip}}" port: "443" enabled_vlans: "all" all_profiles: ['http','clientssl','oneconnect'] pool: "http_pool" snat: "Automap1" .. _step-7-1: Step 7 ------ Next, add the **rescue** stanza. The tasks under the ``rescue`` stanza will be identical to :ref:`Exercise 1.6 - Deleting F5 BIG-IP Configuration<1.6-add-irules>`. The bigip_pool_member task does not need to re-enterered since by deleting the nodes and pool will remove all configuration. If any task within the **block** fails, the **rescue** stanza will execute in order. The VIP, pool, and nodes will be removed gracefully. .. code-block:: yaml rescue: - name: DELETE VIRTUAL SERVER bigip_virtual_server: provider: "{{provider}}" name: "vip" state: absent - name: DELETE POOL bigip_pool: provider: "{{provider}}" name: "http_pool" state: absent - name: DELETE NODES bigip_node: provider: "{{provider}}" name: "{{hostvars[item].inventory_hostname}}" state: absent loop: "{{ groups['webservers'] }}" Step 8 ------ Finally add the **always** to save the running configuration. .. code-block:: yaml --- - name: BIG-IP SETUP hosts: lb connection: local gather_facts: false tasks: - name: Setup provider set_fact: provider: server: "{{private_ip}}" user: "{{ansible_user}}" password: "{{ansible_ssh_pass}}" server_port: "8443" validate_certs: "no" - name: SETUP AND GRACEFUL ROLLBACK BIG-IP CONFIGURATION block: - name: CREATE NODES bigip_node: provider: "{{provider}}" host: "{{hostvars[item].ansible_host}}" name: "{{hostvars[item].inventory_hostname}}" loop: "{{ groups['webservers'] }}" - name: CREATE POOL bigip_pool: provider: "{{provider}}" name: "http_pool" lb_method: "round-robin" monitors: "/Common/http" monitor_type: "and_list" - name: ADD POOL MEMBERS bigip_pool_member: provider: "{{provider}}" state: "present" name: "{{hostvars[item].inventory_hostname}}" host: "{{hostvars[item].ansible_host}}" port: "80" pool: "http_pool" loop: "{{ groups['webservers'] }}" - name: ADD VIRTUAL SERVER bigip_virtual_server: provider: "{{provider}}" name: "vip" destination: "{{private_ip}}" port: "443" enabled_vlans: "all" all_profiles: ['http','clientssl','oneconnect'] pool: "http_pool" snat: "Automap1" rescue: - name: DELETE VIRTUAL SERVER bigip_virtual_server: provider: "{{provider}}" name: "vip" state: absent - name: DELETE POOL bigip_pool: provider: "{{provider}}" name: "http_pool" state: absent - name: DELETE NODES bigip_node: provider: "{{provider}}" name: "{{hostvars[item].inventory_hostname}}" state: absent loop: "{{ groups['webservers'] }}" always: - name: SAVE RUNNING CONFIGURATION bigip_config: provider: "{{provider}}" save: yes The above playbook will try and configure the Virtual Server, Pool and Nodes but since the snat value is provided as ‘Automap1’ the addition of virtual server will fail and the ‘rescue’ block will be run. Step 9 ------ Run the playbook - exit back into the command line of the control host and execute the following: .. code-block:: shell-session [centos@ansible ~]$ ansible-playbook bigip-error-handling.yml Playbook Output =============== .. code-block:: shell-session [centos@ansible ~]$ ansible-playbook bigip-error-handling.yml [centos@ansible ~]$ ansible-playbook bigip-error-handling.yml PLAY [BIG-IP SETUP] **************************************************************************************************** TASK [Setup provider] ************************************************************************************************** ok: [f5] TASK [CREATE NODES] ***************************************************************************************************** changed: [f5] => (item=host1) changed: [f5] => (item=host2) TASK [CREATE POOL] ******************************************************************************************************* changed: [f5] TASK [ADD POOL MEMBERS] ************************************************************************************************************************** changed: [f5] => (item=host1) changed: [f5] => (item=host2) TASK [ADD VIRTUAL SERVER] *************************************************************************************************************************** fatal: [f5]: FAILED! => {"changed": false, "msg": "0107163f:3: Pool (/Common/Automap1) of type (snatpool) doesn't exist."} TASK [DELETE VIRTUAL SERVER] ************************************************************************************************************************** ok: [f5] TASK [DELETE POOL] ************************************************************************************************************************** changed: [f5] TASK [DELETE NODES] ************************************************************************************************************************** changed: [f5] => (item=host1) changed: [f5] => (item=host2) TASK [SAVE RUNNING CONFIGURATION] *************************************************************************************************************************** changed: [f5] PLAY RECAP ***************************************************************************************************************** f5 : ok=8 changed=6 unreachable=0 failed=1 Notice that without the declarative error handling, the Ansible playbook would have stopped here. .. figure:: error.png The work you have been saved is that you don't need to clean the config at the BIG-IP. This declarative ``bigip-error-handling.yml`` Ansible playbook has this done for you. Check the BIG-IP by login to the GUI and check the Local Traffic configuration. Solution ======== The finished Ansible Playbook is provided here for an Answer key. Click here: :download:`bigip-error-handling.yml <./bigip-error-handling.yml>`. You have finished this exercise. `Click here to return to the lab guide <..>`__