diff --git a/docs/class14/README.md b/docs/class14/README.md new file mode 100644 index 00000000..84f96abe --- /dev/null +++ b/docs/class14/README.md @@ -0,0 +1 @@ +# AppWorld24Ansible101 \ No newline at end of file diff --git a/docs/class14/class14.rst b/docs/class14/class14.rst new file mode 100644 index 00000000..0d11a132 --- /dev/null +++ b/docs/class14/class14.rst @@ -0,0 +1,14 @@ +Class 14: Basic BIG-IP Configuration Management with Ansible +=========================================================== + +During this lab you will make use of Ansible +to deploy and configure a BIG-IP instance. + +Expected time to complete: **1 hour, 30 minutes** + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + :glob: + + module*/module* diff --git a/docs/class14/images/ansiblef5-large.png b/docs/class14/images/ansiblef5-large.png new file mode 100644 index 00000000..a5eaf95d Binary files /dev/null and b/docs/class14/images/ansiblef5-large.png differ diff --git a/docs/class14/images/ansiblef5-transparent-large.png b/docs/class14/images/ansiblef5-transparent-large.png new file mode 100644 index 00000000..5338c6a9 Binary files /dev/null and b/docs/class14/images/ansiblef5-transparent-large.png differ diff --git a/docs/class14/images/ansiblef5-transparent.png b/docs/class14/images/ansiblef5-transparent.png new file mode 100644 index 00000000..21479863 Binary files /dev/null and b/docs/class14/images/ansiblef5-transparent.png differ diff --git a/docs/class14/images/ansiblef5.png b/docs/class14/images/ansiblef5.png new file mode 100644 index 00000000..df0692ff Binary files /dev/null and b/docs/class14/images/ansiblef5.png differ diff --git a/docs/class14/images/diagram.png b/docs/class14/images/diagram.png new file mode 100644 index 00000000..1feeaa3a Binary files /dev/null and b/docs/class14/images/diagram.png differ diff --git a/docs/class14/images/f5topology.png b/docs/class14/images/f5topology.png new file mode 100644 index 00000000..eecb6367 Binary files /dev/null and b/docs/class14/images/f5topology.png differ diff --git a/docs/class14/images/japan.png b/docs/class14/images/japan.png new file mode 100644 index 00000000..e229f178 Binary files /dev/null and b/docs/class14/images/japan.png differ diff --git a/docs/class14/images/network_diagram.png b/docs/class14/images/network_diagram.png new file mode 100644 index 00000000..b706dad8 Binary files /dev/null and b/docs/class14/images/network_diagram.png differ diff --git a/docs/class14/images/networkautomation.png b/docs/class14/images/networkautomation.png new file mode 100644 index 00000000..59dab438 Binary files /dev/null and b/docs/class14/images/networkautomation.png differ diff --git a/docs/class14/images/rh-ansible-automation-platform.png b/docs/class14/images/rh-ansible-automation-platform.png new file mode 100644 index 00000000..c607a917 Binary files /dev/null and b/docs/class14/images/rh-ansible-automation-platform.png differ diff --git a/docs/class14/images/rh-ansible-automation.png b/docs/class14/images/rh-ansible-automation.png new file mode 100644 index 00000000..2f931b40 Binary files /dev/null and b/docs/class14/images/rh-ansible-automation.png differ diff --git a/docs/class14/images/uk.png b/docs/class14/images/uk.png new file mode 100644 index 00000000..285e0a87 Binary files /dev/null and b/docs/class14/images/uk.png differ diff --git a/docs/class14/module1/0.0-getting-started.rst b/docs/class14/module1/0.0-getting-started.rst new file mode 100644 index 00000000..232ab2c9 --- /dev/null +++ b/docs/class14/module1/0.0-getting-started.rst @@ -0,0 +1,63 @@ +.. _0.0-getting-started: + +Exercise 0.0: Getting Started +########################################### + +During this lab Visual Studio Code will be used as the editor of choice and also provides a terminal to run Ansible playbooks and watch the logging accordingly. + +Follow the steps below to start using VS Code in your local browser during this lab. + +Step 1 +------ + +If you already haven't done so. Use the UDF deployment to go to the **Documentation** section and grab the lab guide: https://clouddocs.f5.com/training/community/automation/html/class09/class09.html |labguide| + +.. |labguide| image:: labguide.png + +Step 2 +------ + +In the UDF deployment, go to the **Deployment** section, search the **Ansible host** and click **Access** and select **VS Code**. |vscode_access| + +.. |vscode_access| image:: vscode_access.png + +Your local browser will start up VS Code. + +Step 3 +------ + +Check the box to Trust the authors and click the button **Yes, I trust...**. + +**Ignore** the pop-up error windows in the bottom-right of your browser by **closing** them. + +Step 4 +------ + +Go to the left side of the screen and select the **three stripes**. Then go to **Terminal** and select **New Terminal**. |terminal| + +.. |terminal| image:: terminal.png + +The **Terminal Pane** section will appear at the bottom and change the view from **Output** to **Terminal**. |vscode_pane| + +.. |vscode_pane| image:: vscode_pane.png + + +You can use the **terminal Pane** to launch **Ansible playbooks** and execute **Shell** commands during the lab. + +Step 5 +------ +Note: There are copies of the lab scripts located under the folder "networking-workshop" in the explorer pane on the left that can be used for error checking and copy/paste needs. + +**Note 2: When you navigate to the folders and click files the Terminal may switch back to Ouput and errors may pop up on bottom right. Just click back to Terminal tab and close the error pop ups.** + +In order to be able to deploy those Ansible playbooks, you need to create YAML scripts which will become your ansible-playbooks. +In **VS Code Explorer** in an empty space ``right-click`` and select **New File**. You do not need to actually create a file at this time so you can just click away to close. Or you can name it testing123.yml if you wish. |new_file| + +.. |new_file| image:: new_file.png + +.. + + Note: Make sure you right-click in the 'empty' grey area. When you right-click at the height of the folder section and create a new file, that file will end up in that selected folder. + + +You finished the **Getting Started** section. \ No newline at end of file diff --git a/docs/class14/module1/1.0-explore.rst b/docs/class14/module1/1.0-explore.rst new file mode 100644 index 00000000..2b035925 --- /dev/null +++ b/docs/class14/module1/1.0-explore.rst @@ -0,0 +1,157 @@ +.. _1.0-explore: + +Exercise 1.0: Exploring the lab environment +########################################### + +Step 1 +------ + +In the VS Code terminal section, navigate to the ``networking-workshop`` directory. + +.. code-block:: shell-session + + [centos@ansible ~]$ cd networking-workshop/ + [centos@ansible networking-workshop]$ + +Step 2 +------ + +Run the ``ansible`` command with the ``--version`` command to look at +what is configured: + +.. code-block:: shell-session + + [centos@ansible networking-workshop]$ ansible --version + ansible [core 2.12.4] + config file = /home/centos/.ansible.cfg + configured module search path = ['/home/centos/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] + ansible python module location = /home/centos/.local/lib/python3.8/site-packages/ansible + ansible collection location = /home/centos/.ansible/collections:/usr/share/ansible/collections + executable location = /home/centos/.local/bin/ansible + python version = 3.8.12 (default, Mar 31 2022, 14:42:38) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] + jinja version = 3.1.1 + libyaml = True + +.. + + Note: The Ansible version you see might differ from the above output + +This command gives you information about the version of Ansible, +location of the executable, version of Python, search path for the +modules and location of the ``ansible configuration file``. + +Step 3 +------ + +Use the ``cat`` command to view the contents of the ``ansible.cfg`` +file. + +.. code-block:: shell-session + :emphasize-lines: 5,7 + + [centos@ansible networking-workshop]$ cat ~/.ansible.cfg + [defaults] + connection = smart + timeout = 60 + inventory = /home/centos/networking-workshop/lab_inventory/hosts + host_key_checking = False + private_key_file = /home/centos/.ssh/aws-private.pem + [centos@ansible networking-workshop]$ + +Note the following parameters within the ``ansible.cfg`` file: + +- ``inventory``: shows the location of the ansible inventory being used +- ``private_key_file``: this shows the location of the private key used + to login to devices (this won’t be present for UDF, we will use the + default key) + +Step 4 +------ + +The scope of a ``play`` within a ``playbook`` is limited to the groups +of hosts declared within an Ansible **inventory**. Ansible supports +multiple +`inventory `__ +types. An inventory could be a simple flat file with a collection of +hosts defined within it or it could be a dynamic script (potentially +querying a CMDB backend) that generates a list of devices to run the +playbook against. + +In this lab you will work with a file based inventory written in the +**ini** format. Use the ``cat`` command to view the contents of your +inventory: + +``[centos@ansible networking-workshop]$ cat lab_inventory/hosts`` + +The output will look similar to as follows: + +.. code-block:: yaml + + [all:vars] + ansible_user=centos + ansible_ssh_pass=f5ansible + ansible_ssh_private_key_file=/home/centos/.ssh/aws-private.pem + + [lb] + f5 ansible_host=10.1.20.7 ansible_user=admin private_ip=10.1.1.7 destination_ip=10.1.20.100 ansible_ssh_pass=f5ansible + + [control] + ansible ansible_host=10.1.1.4 ansible_user=centos + + [webservers] + host1 ansible_host=10.1.20.5 ansible_user=centos private_ip=10.1.1.5 + host2 ansible_host=10.1.20.6 ansible_user=centos private_ip=10.1.1.6 + +.. + + Note that the IP addresses will be different in your environment. + +Step 5 +------ + +In the above output every ``[ ]`` defines a group. For example +``[webservers]`` is a group that contains the hosts ``host1`` and +``host2``. + + Note: A group called **all** always exists and contains all groups + and hosts defined within an inventory. + +We can associate variables to groups and hosts. Host variables are +declared/defined on the same line as the host themselves. For example +for the host ``f5``: + +.. code-block:: yaml + + f5 ansible_host=10.1.20.7 ansible_user=admin private_ip=10.1.1.7 destination_ip=10.1.20.100 ansible_ssh_pass=f5ansible + +- ``f5`` - The name that Ansible will use. This can but does not have + to rely on DNS +- ``ansible_host`` - The IP address that ansible will use, if not + configured it will default to DNS +- ``ansible_user`` - The user ansible will use to login to this host, + if not configured it will default to the user the playbook is run + from +- ``private_ip`` - This value is not reserved by ansible so it will + default to a `host + variable `__. + This variable can be used by playbooks or ignored completely. +- ``destination_ip`` - This value is not reserved either, we are + using it to define the Virtual Server IP we want. +- ``ansible_ssh_pass`` - The password ansible will use to login to this + host, if not configured it will assume the user the playbook ran from + has access to this host through SSH keys. + +.. + + Does the password have to be in plain text? No, Red Hat Ansible Tower + can take care of credential management in an easy to use web GUI or a + user may use + `ansible-vault `__ + +Go back to the home directory + +.. code-block:: shell-session + + [centos@ansible networking-workshop]$ cd ~ + +You have finished this exercise. diff --git a/docs/class14/module1/1.1-get-facts.rst b/docs/class14/module1/1.1-get-facts.rst new file mode 100644 index 00000000..6b45287b --- /dev/null +++ b/docs/class14/module1/1.1-get-facts.rst @@ -0,0 +1,351 @@ +.. _1.1-get-facts: + +Exercise 1.1: Using the bigip_device_info module +################################################ + +Objective +========= + +Demonstrate use of the `BIG-IP Facts +module `__ +to grab facts (useful information) from a F5 BIG-IP device and display +them to the terminal window using the `debug +module `__. + +Guide +===== + +Note: There are copies of the lab scripts located under the folder "networking-workshop" in the explorer pane on the left that can be used for error checking and copy/paste needs. + +Make sure you are in the home directory + +.. code-block:: shell-session + + [centos@ansible networking-workshop]$ cd ~ + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-facts.yml``. + +.. + + The Ansible node is equipped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 2: +------- + +Ansible playbooks are **YAML** files. YAML is a structured encoding +format that is also extremely human readable (unlike it’s subset - the +JSON format). + +Enter the following play definition into ``bigip-facts.yml``: + +.. code-block:: yaml + + --- + - name: GRAB F5 FACTS + hosts: f5 + connection: local + gather_facts: no + +- 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: no`` disables facts gathering. We are not using any + fact variables for this playbook. + +Do not close editor yet. + +Step 3 +------ + +Next, add the first ``task``. This task will use the +``bigip_device_info`` module to grab useful information from the BIG-IP +device. + +.. warning:: + The ``tasks:`` item should line up to the same indentation as ``gather_facts:`` + while the ``- name:`` item should be indented 2 spaces under ``tasks:`` + +.. code-block:: yaml + + tasks: + + - name: COLLECT BIG-IP FACTS + bigip_device_info: + gather_subset: + - system-info + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + register: device_facts + +.. + + A play is a list of tasks. Tasks and modules have a 1:1 correlation. + Ansible modules are reusable, standalone scripts that can be used by + the Ansible API, or by the ansible or ansible-playbook programs. They + return information to ansible by printing a JSON string to stdout + before exiting. + +- ``name: COLLECT BIG-IP FACTS`` is a user defined description that + will display in the terminal output. +- ``bigip_device_info:`` tells the task which module to use. Everything + except ``register`` is a module parameter defined on the module + documentation page. +- The ``gather_subset: system_info`` parameter tells the module only to + grab system level information. +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The\ ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with. 8443 is what’s being used in + this lab, but could be different depending on the deployment. +- ``register: device_facts`` tells the task to save the output to a + variable bigip_device_info + +Step 4 +------ + +Next, append the second ``task`` to above . This task will use the +``debug`` module to print the output from device_facts variable we +registered the facts to. + +.. code-block:: yaml + + - name: DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION + debug: + var: device_facts + +- The ``name: COMPLETE BIG-IP SYSTEM INFORMATION`` is a user defined + description that will display in the terminal output. +- ``debug:`` tells the task to use the debug module. +- The ``var: device_facts`` parameter tells the module to display the + variable bigip_device_info. + +Save the file and exit out of editor. + +Step 5 +------ + +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-facts.yml + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook bigip-facts.yml + + PLAY [GRAB F5 FACTS] ***************************************************************************************************************************************** + + TASK [COLLECT BIG-IP FACTS] ********************************************************************************************************************************** + ok: [f5] + + TASK [DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION] ************************************************************************************************************ + ok: [f5] => + device_facts: + ansible_facts: + discovered_interpreter_python: /usr/bin/python + changed: false + failed: false + queried: true + system_info: + base_mac_address: 06:95:66:ab:b6:1c + chassis_serial: a2ad2fec-c283-2cc9-3610e7425914 + hardware_information: + - model: Intel(R) Xeon(R) CPU E5-2666 v3 @ 2.90GHz + name: cpus + type: base-board + versions: + - name: cpu stepping + version: '2' + - name: cpu sockets + version: '1' + - name: cpu MHz + version: '2900.042' + - name: cores + version: 8 (physical:4) + - name: cache size + version: 25600 KB + marketing_name: BIG-IP Virtual Edition + package_edition: Final + package_version: Build 0.0.11 - Fri Aug 2 21:38:03 PDT 2019 + platform: Z100 + product_build: 0.0.11 + product_build_date: Fri Aug 2 21:38:03 PDT 2019 + product_built: 190802213803 + product_changelist: 3115640 + product_code: BIG-IP + product_jobid: 1128587 + product_version: 15.0.1 + time: + day: 19 + hour: 15 + minute: 41 + month: 2 + second: 1 + year: 2020 + uptime: 9380.0 + + PLAY RECAP *************************************************************************************************************************************************** + f5 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + +Step 6 +------ + +Finally let’s append two more tasks to get more specific info from facts +gathered, to the above playbook. + +.. code-block:: yaml + + - name: DISPLAY ONLY THE MAC ADDRESS + debug: + var: device_facts['system_info']['base_mac_address'] + + - name: DISPLAY ONLY THE VERSION + debug: + var: device_facts['system_info']['product_version'] + +- ``var: device_facts['system_info']['base_mac_address']`` displays the + MAC address for the Management IP on the BIG-IP device +- ``device_facts['system_info']['product_version']`` displays the + product version BIG-IP device + +.. + + Because the bigip_device_info module returns useful information in + structured data, it is really easy to grab specific information + without using regex or filters. Fact modules are very powerful tools + to grab specific device information that can be used in subsequent + tasks, or even used to create dynamic documentation (reports, csv + files, markdown). + +Step 7 +------ + +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-facts.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook bigip-facts.yml + + PLAY [GRAB F5 FACTS] ***************************************************************************************************************************************** + + TASK [COLLECT BIG-IP FACTS] ********************************************************************************************************************************** + ok: [f5] + + TASK [DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION] ************************************************************************************************************ + ok: [f5] => + device_facts: + ansible_facts: + discovered_interpreter_python: /usr/bin/python + changed: false + failed: false + queried: true + system_info: + base_mac_address: 06:95:66:ab:b6:1c + chassis_serial: a2ad2fec-c283-2cc9-3610e7425914 + hardware_information: + - model: Intel(R) Xeon(R) CPU E5-2666 v3 @ 2.90GHz + name: cpus + type: base-board + versions: + - name: cpu stepping + version: '2' + - name: cpu sockets + version: '1' + - name: cpu MHz + version: '2900.042' + - name: cores + version: 8 (physical:4) + - name: cache size + version: 25600 KB + marketing_name: BIG-IP Virtual Edition + package_edition: Final + package_version: Build 0.0.11 - Fri Aug 2 21:38:03 PDT 2019 + platform: Z100 + product_build: 0.0.11 + product_build_date: Fri Aug 2 21:38:03 PDT 2019 + product_built: 190802213803 + product_changelist: 3115640 + product_code: BIG-IP + product_jobid: 1128587 + product_version: 15.0.1 + time: + day: 19 + hour: 15 + minute: 42 + month: 2 + second: 4 + year: 2020 + uptime: 9443.0 + + TASK [DISPLAY ONLY THE MAC ADDRESS] ************************************************************************************************************************** + ok: [f5] => + device_facts['system_info']['base_mac_address']: 06:95:66:ab:b6:1c + + TASK [DISPLAY ONLY THE VERSION] ****************************************************************************************************************************** + ok: [f5] => + device_facts['system_info']['product_version']: 15.0.1 + + PLAY RECAP *************************************************************************************************************************************************** + f5 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here for :download:`bigip-facts.yml <./bigip-facts.yml>`. + +Going Further +============= + +For this bonus exercise add the ``tags: debug`` paramteter (at the task +level) to the existing debug task. + +.. code-block:: yaml + + - name: DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION + debug: + var: device_facts + tags: debug + +Now re-run the playbook with the ``--skip-tags-debug`` command line +option. + +.. code-block:: shell-session + + ansible-playbook bigip-facts.yml --skip-tags=debug + +The Ansible Playbook will only run three tasks, skipping the +``DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION`` task. + +You have finished this exercise. diff --git a/docs/class14/module1/1.2-add-node.rst b/docs/class14/module1/1.2-add-node.rst new file mode 100644 index 00000000..8290b7a5 --- /dev/null +++ b/docs/class14/module1/1.2-add-node.rst @@ -0,0 +1,162 @@ +.. _1.2-add-node: + +Exercise 1.2: Adding nodes to F5 BIG-IP +####################################### + +Objective +========= + +Demonstrate use of the `BIG-IP node +module `__ +to add two RHEL (Red Hat Enterprise Linux) web servers as nodes for the +BIG-IP load balancer. + +Guide +===== + +Step 1: +------- + +Login to the F5 with your web browser to see what was configured before you push changes to the device. +To access the BIG-IP go to the lab dashboard and on the BIG-IP select Access, TMUI and login with +the admin user credentials noted in the lab guide. + +Use VS Code Explorer to create a new file called ``bigip-node.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-node.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: lb``, indicates the play is run only on the lb group. + Technically there only one F5 device but if there were multiple they + would be configured simultaneously. +- ``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. + +Do not close the editor yet. + +Step 3 +------ + +Next, append the first ``task`` to above playbook. This task will use +the ``bigip_node`` module configure the two RHEL web servers as nodes on +the BIG-IP F5 load balancer. + +.. code-block:: yaml + + tasks: + + - name: CREATE NODES + bigip_node: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + host: "{{hostvars[item].ansible_host}}" + name: "{{hostvars[item].inventory_hostname}}" + loop: "{{ groups['webservers'] }}" + +.. + + A + `loop `__ + will repeat a task on a list provided to the task. In this case it + will loop twice, once for each of the two web servers. + +- ``name: CREATE NODES`` is a user defined description that will + display in the terminal output. +- ``bigip_node:`` tells the task which module to use. Everything except + ``loop`` is a module parameter defined on the module documentation + page. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with +- The ``host: "{{hostvars[item].ansible_host}}"`` parameter tells the + module to add a web server IP address already defined in our + inventory. +- The ``name: "{{hostvars[item].inventory_hostname}}"`` parameter tells + the module to use the ``inventory_hostname`` as the name (which will + be host1 and host2). +- The ``validate_certs: "no"`` parameter tells the module to not + validate SSL certificates. This is just used for demonstration + purposes since this is a lab. +- ``loop:`` tells the task to loop over the provided list. The list in + this case is the group webservers which includes two RHEL hosts. + +Save the file and exit out of editor. + +Step 4 +------ + +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-node.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: yaml + + [centos@ansible]$ ansible-playbook bigip-node.yml + + PLAY [BIG-IP SETUP] ************************************************************ + + TASK [CREATE NODES] ************************************************************ + changed: [f5] => (item=host1) + changed: [f5] => (item=host2) + + PLAY RECAP ********************************************************************* + f5 : ok=1 changed=1 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-node.yml <./bigip-node.yml>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor, defaults to f5ansible** + +The list of nodes can be found by navigating the menu on the left. Click +on Local Traffic-> then click on Nodes. |f5web| + +You have finished this exercise. + +.. |f5web| image:: nodes.png diff --git a/docs/class14/module1/1.3-add-pool.rst b/docs/class14/module1/1.3-add-pool.rst new file mode 100644 index 00000000..21ce0298 --- /dev/null +++ b/docs/class14/module1/1.3-add-pool.rst @@ -0,0 +1,153 @@ +.. _1.3-add-pool: + +Exercise 1.3: Adding a load balancing pool +########################################## + +Objective +========= + +Demonstrate use of the `BIG-IP pool +module `__ +to configure a load balancing pool in BIG-IP device. A load balancing +pool is a logical set of devices, such as web servers, that you group +together to receive and process traffic. + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-pool.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-pool.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: lb``, indicates the play is run only on the lb group. + Technically there only one F5 device but if there were multiple they + would be configured simultaneously. +- ``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. + +Do not exit the editor yet. + +Step 3 +------ + +Next, append the first ``task`` to above playbook. This task will use +the ``bigip_pool`` module configure the two RHEL web servers as nodes on +the BIG-IP F5 load balancer. + +.. code-block:: yaml + + tasks: + + - name: CREATE POOL + bigip_pool: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + name: "http_pool" + lb_method: "round-robin" + monitors: "/Common/http" + monitor_type: "and_list" + +- ``name: CREATE POOL`` is a user defined description that will display + in the terminal output. +- ``bigip_pool:`` tells the task which module to use. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with +- The ``name: "http_pool"`` parameter tells the module to create a pool + named http_pool +- The ``lb_method: "round-robin"`` parameter tells the module the load + balancing method will be round-robin. A full list of methods can be + found on the documentation page for bigip_pool. +- The ``monitors: "/Common/http"`` parameter tells the module the that + the http_pool will only look at http traffic. +- The ``monitor_type: "and_list"`` ensures that all monitors are + checked. +- The ``validate_certs: "no"`` parameter tells the module to not + validate SSL certificates. This is just used for demonstration + purposes since this is a lab. + +Save the file and exit out of editor + +Step 4 +------ + +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-pool.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook bigip-pool.yml + + PLAY [BIG-IP SETUP] ************************************************************ + + TASK [CREATE POOL] ************************************************************* + changed: [f5] + + PLAY RECAP ********************************************************************* + f5 : ok=1 changed=1 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-pool.yml <./bigip-pool.yml>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. Grab +the IP information for the F5 load balancer from the lab_inventory/hosts +file, and type it in like so: https://X.X.X.X:8443/ + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor, defaults to f5ansible** + +The load balancer pool can be found by navigating the menu on the left. +Click on Local Traffic-> then click on Pools. |f5pool| + +You have finished this exercise. + +.. |f5pool| image:: pool.png diff --git a/docs/class14/module1/1.4-add-pool-members.rst b/docs/class14/module1/1.4-add-pool-members.rst new file mode 100644 index 00000000..7ed0bf1e --- /dev/null +++ b/docs/class14/module1/1.4-add-pool-members.rst @@ -0,0 +1,295 @@ +.. _1.4-add-pool-members: + +Exercise 1.4: Adding members to a pool on F5 +############################################ + +Objective +========= + +Demonstrate use of the `BIG-IP pool member +module `__ +to tie web server nodes into the load balancing pool ``http_pool`` +created in the previous exercises. + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-pool-members.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-pool-members.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: lb``, indicates the play is run only on the lb group. + Technically there only one F5 device but if there were multiple they + would be configured simultaneously. +- ``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. + +Do not exit the editor yet. + +Step 3 +------ + +Next, append the first ``task`` to above playbook. This task will use +the ``bigip_pool_member`` module configure the two RHEL web servers as +nodes on the BIG-IP F5 load balancer. + +.. code-block:: yaml + + tasks: + + - name: ADD POOL MEMBERS + bigip_pool_member: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + state: "present" + name: "{{hostvars[item].inventory_hostname}}" + host: "{{hostvars[item].ansible_host}}" + port: "80" + pool: "http_pool" + loop: "{{ groups['webservers'] }}" + +Explanation of each line within the task: - ``name: ADD POOL MEMBERS`` +is a user defined description that will display in the terminal output. +- ``bigip_pool_member:`` tells the task which module to use. + +Next we have module parameters - The ``server: "{{private_ip}}"`` +parameter tells the module to connect to the F5 BIG-IP IP address, which +is stored as a variable ``private_ip`` in inventory - The ``provider:`` +parameter is a group of connection details for the BIG-IP. - The +``user: "{{ansible_user}}"`` parameter tells the module the username to +login to the F5 BIG-IP device with - The +``password: "{{ansible_ssh_pass}}"`` parameter tells the module the +password to login to the F5 BIG-IP device with - The +``server_port: 8443`` parameter tells the module the port to connect to +the F5 BIG-IP device with - The ``state: "present"`` parameter tells the +module we want this to be added rather than deleted. - The +``name: "{{hostvars[item].inventory_hostname}}"`` parameter tells the +module to use the ``inventory_hostname`` as the name (which will be +host1 and host2). - The ``host: "{{hostvars[item].ansible_host}}"`` +parameter tells the module to add a web server IP address already +defined in our inventory. - The ``port``: parameter tells the pool +member port. - The ``pool: "http_pool"`` parameter tells the module to +put this node into a pool named http_pool - The ``validate_certs: "no"`` +parameter tells the module to not validate SSL certificates. This is +just used for demonstration purposes since this is a lab. Finally there +is a loop parameter which is at the task level (it is not a module +parameter but a task level parameter: - ``loop:`` tells the task to loop +over the provided list. The list in this case is the group webservers +which includes two RHEL hosts. + +Save the file and exit out of editor. + +Step 4 +------ + +Run the playbook - exit back into the command line of the control host +and execute the following: + +.. code-block:: shell-session + + [student1@ansible ~]$ ansible-playbook bigip-pool-members.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: yaml + + [student1@ansible ~]$ ansible-playbook bigip-pool-members.yml + + PLAY [BIG-IP SETUP] ************************************************************ + + TASK [ADD POOL MEMBERS] ******************************************************** + changed: [f5] => (item=host1) + changed: [f5] => (item=host2) + + PLAY RECAP ********************************************************************* + f5 : ok=1 changed=1 unreachable=0 failed=0 + +Output parsing +============== + +Let’s use the bigip_device_info to collect the pool members on BIG-IP. +`JSON +query `__ +is a powerful filter that can be used. Please go through before +proceeding. + +Use VS Code Explorer to create a new file called ``display-pool-members.yml``. + +Enter the following: + +.. code-block:: yaml + + --- + - name: "List pool members" + hosts: lb + gather_facts: false + connection: local + + tasks: + + - name: Query BIG-IP facts + bigip_device_info: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: "no" + gather_subset: + - ltm-pools + register: bigip_device_facts + + - name: "View complete output" + debug: "msg={{bigip_device_facts}}" + + - name: "Show members belonging to pool" + debug: "msg={{item}}" + loop: "{{bigip_device_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='http_pool'].members[*].name[]" + +- ``vars:`` in the module is defining a variable query_string to be + used within the module itself +- ``query_String`` will have the name of all members from pool name + ‘http_pool’. query_string is defined to make it easier to read the + entire json string + +Execute the playbook + +.. code-block:: shell-session + + [student1@ansible ~]$ ansible-playbook display-pool-members.yml + +Output + +.. code-block:: yaml + + [student1@ansible 1.4-add-pool-members]$ ansible-playbook display-pool-members.yml + + PLAY [List pool members] ****************************************************************************************************************************************************************************** + + TASK [Query BIG-IP facts] ***************************************************************************************************************************************************************************** + changed: [f5] + + TASK [View complete output] *************************************************************************************************************************************************************************** + ok: [f5] => + msg: + changed: true + ltm_pools: + - allow_nat: 'yes' + allow_snat: 'yes' + client_ip_tos: pass-through + client_link_qos: pass-through + full_path: /Common/http_pool + ignore_persisted_weight: 'no' + lb_method: round-robin + members: + - address: 54.191.xx.xx + connection_limit: 0 + dynamic_ratio: 1 + ephemeral: 'no' + fqdn_autopopulate: 'no' + full_path: /Common/host1:80 + inherit_profile: 'yes' + logging: 'no' + monitors: [] + name: host1:80 + partition: Common + priority_group: 0 + rate_limit: 'no' + ratio: 1 + state: disabled + - address: 54.200.xx.xx + connection_limit: 0 + dynamic_ratio: 1 + ephemeral: 'no' + fqdn_autopopulate: 'no' + full_path: /Common/host2:80 + inherit_profile: 'yes' + logging: 'no' + monitors: [] + name: host2:80 + partition: Common + priority_group: 0 + rate_limit: 'no' + ratio: 1 + state: disabled + minimum_active_members: 0 + minimum_up_members: 0 + minimum_up_members_action: failover + minimum_up_members_checking: 'no' + monitors: + - /Common/http + name: http_pool + priority_group_activation: 0 + queue_depth_limit: 0 + queue_on_connection_limit: 'no' + queue_time_limit: 0 + reselect_tries: 0 + server_ip_tos: pass-through + server_link_qos: pass-through + service_down_action: none + slow_ramp_time: 10 + + TASK [Show members belonging to pool] ***************************************************************************************************************************************************************** + ok: [f5] => (item=host1:80) => + msg: host1:80 + ok: [f5] => (item=host2:80) => + msg: host2:80 + + PLAY RECAP ******************************************************************************************************************************************************************************************** + f5 : ok=3 changed=1 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-pool-members.yml <./bigip-pool-members.yml>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. Grab +the IP information for the F5 load balancer from the lab_inventory/hosts +file, and type it in like so: https://X.X.X.X:8443/ + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor** defaults to f5ansible + +The pool will now show two members (host1 and host2). Click on Local +Traffic-> then click on Pools. Click on http_pool to get more granular +information. Click on the Members tab in the middle to list all the +Members. |f5members| + +You have finished this exercise. + +.. |f5members| image:: poolmembers.png diff --git a/docs/class14/module1/1.5-add-virtual-server.rst b/docs/class14/module1/1.5-add-virtual-server.rst new file mode 100644 index 00000000..eefd233e --- /dev/null +++ b/docs/class14/module1/1.5-add-virtual-server.rst @@ -0,0 +1,214 @@ +.. _1.5-add-virtual-server: + +Exercise 1.5: Using the bigip_virtual_server module +################################################### + +Objective +========= + +Demonstrate use of the `BIG-IP virtual server +module `__ +to configure a virtual server on the BIG-IP. Virtual server is a +combination of IP:Port. + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-virtual-server.yml``. + +.. + + The Ansible node is equiped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 2: +------- + +Ansible playbooks are **YAML** files. YAML is a structured encoding +format that is also extremely human readable (unlike it’s subset - the +JSON format). + +Enter the following play definition into ``bigip-virtual-server.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: no`` disables facts gathering. We are not using any + fact variables for this playbook. + +Do not exit the editor yet. + +Step 3 +------ + +Next, append the ``task`` to above playbook. This task will use the +``bigip-virtual-server`` to configure a virtual server on the BIG-IP + +.. code-block:: yaml + + tasks: + + - name: ADD VIRTUAL SERVER + bigip_virtual_server: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + name: "vip" + destination: "{{destination_ip}}" + port: "443" + enabled_vlans: "all" + all_profiles: ['http','clientssl','oneconnect'] + pool: "http_pool" + snat: "Automap" + +.. + + A play is a list of tasks. Tasks and modules have a 1:1 correlation. + Ansible modules are reusable, standalone scripts that can be used by + the Ansible API, or by the ansible or ansible-playbook programs. They + return information to ansible by printing a JSON string to stdout + before exiting. + +- ``name: ADD VIRTUAL SERVER`` is a user defined description that will + display in the terminal output. +- ``bigip_virtual_server:`` tells the task which module to use. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The\ ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with +- The ``name: "vip"`` parameter tells the module to create a virtual + server named vip +- The ``destination"`` parameter tells the module which IP address to + assign for the virtual server +- The ``port`` paramter tells the module which Port the virtual server + will be listening on +- The ``enabled_vlans`` parameter tells the module which all vlans the + virtual server is enbaled for +- The ``all_profiles`` paramter tells the module which all profiles are + assigned to the virtuals server +- The ``pool`` parameter tells the module which pool is assigned to the + virtual server +- The ``snat`` paramter tells the module what the Source network + address address should be. In this module we are assigning it to be + Automap which means the source address on the request that goes to + the backend server will be the self-ip address of the BIG-IP +- The ``validate_certs: "no"`` parameter tells the module to not + validate SSL certificates. This is just used for demonstration + purposes since this is a lab. + +Save the file and exit out of editor + +Step 4 +------ + +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-virtual-server.yml + +Playbook Output +=============== + +.. code-block:: yaml + + [centos@ansible]$ ansible-playbook bigip-virtual-server.yml + + PLAY [BIG-IP SETUP]************************************************************* + + TASK [ADD VIRTUAL SERVER] ****************************************************** + changed: [f5] + + PLAY RECAP ********************************************************************* + f5 : ok=1 changed=1 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-virtual-server.yml <./bigip-virtual-server.yml>`. + +Verifying the Solution +====================== + +To see the configured **Virtual Server**, login to the F5 load balancer +with your web browser. + + Grab the IP information for the F5 load balancer from the + ``/home/studentX/networking_workshop/lab_inventory/hosts`` file, and + type it in like so: https://X.X.X.X:8443/ + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor** defaults to f5ansible + +The load balancer virtual server can be found by navigating the menu on +the left. Click on **Local Traffic**. then click on **Virtual Server**. +See the screenshot below: |f5 vip image| + +Verifying the web servers +------------------------- + +Each Centos web server actually already has apache running. Exercise 1.1 +through 1.5 have successfully setup the load balancer for the pool of +web servers. Open up the public IP of the F5 load balancer in your web +browser: + + This time use port 443 instead of 8443, e.g. https://X.X.X.X:443/ + +.. note:: + In your environment, go to the f5 component and use the + ``HTTPS Virtual Server Test`` access method to test. + +Each time you refresh the host will change between **host1** and +**host2**. Here is animation of the host field changing: |apptest| +>the animation might not work on certain browsers +>the 'Agility' animation will say **F5 Agility 2022** + +Alternate Verification Method +----------------------------- + +Instead of using a browser window it is also possible to use the command +line on the Ansible control node. Use the ``curl`` command on the +**ansible_host** to access public IP or private IP address of F5 load +balancer in combination with the ``--insecure`` and ``--silent`` command +line arguments. Since the entire website is loaded on the command line +it is recommended to ``| grep`` for the student number assigned to the +respective workbench. (e.g. student5 would ``| grep student5``) + +:: + + [centos@ansible ~]$ curl https://10.1.20.100:443 --insecure --silent +

F5 Agility 2022 - HOST1

+ [centos@ansible ~]$ curl https://10.1.20.100:443 --insecure --silent +

F5 Agility 2022 - HOST2

+ [centos@ansible ~]$ curl https://10.1.20.100:443 --insecure --silent +

F5 Agility 2022 - HOST1

+ +You have finished this exercise. + +.. |f5 vip image| image:: f5vip.png +.. |apptest| image:: apptest.png diff --git a/docs/class14/module1/1.6-add-irules.rst b/docs/class14/module1/1.6-add-irules.rst new file mode 100644 index 00000000..8905ef56 --- /dev/null +++ b/docs/class14/module1/1.6-add-irules.rst @@ -0,0 +1,230 @@ +.. _1.6-add-irules: + +Exercise 1.6: Using the bigip_irule module +########################################## + +Objective +========= + +Demonstrate use of the `BIG-IP irule +module `__ +to add iRules to a BIG-IP and then attach the iRules to a virtual +server. + +Guide +===== + +Step 1 +------ + +Create two dummy irules with the names ‘irule1’ and ‘irule2’ + +.. code-block:: shell-session + + [centos@ansible ~]$ nano irule1 + + when HTTP_REQUEST { + log local0. "Accessing iRule1" + } + +Save the file + +.. code-block:: shell-session + + [centos@ansible ~]$ nano irule2 + + when HTTP_REQUEST { + log local0. "Accessing iRule2" + } + +Save the file + +Step 2: +------- + +Use VS Code Explorer to create a new file called ``bigip-irule.yml``. + +.. + + The Ansible node is equipped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 3: +------- + +Ansible playbooks are **YAML** files. YAML is a structured encoding +format that is also extremely human readable (unlike it’s subset - the +JSON format). + +Enter the following play definition into ``bigip-irule.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: no`` disables facts gathering. We are not using any + fact variables for this playbook. + +Save and Exit out of editor. + +Step 4 +------ + +Next, add the ``vars`` and ``tasks`` stanzas. This task will use the ``bigip-irule`` to add irules to the BIG-IP. + + +.. code-block:: yaml + + vars: + irules: ['irule1','irule2'] + + tasks: + + - name: ADD iRules + bigip_irule: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + module: "ltm" + name: "{{item}}" + content: "{{lookup('file','{{item}}')}}" + with_items: "{{irules}}" + +.. + + A play is a list of tasks. Tasks and modules have a 1:1 correlation. + Ansible modules are reusable, standalone scripts that can be used by + the Ansible API, or by the ansible or ansible-playbook programs. They + return information to ansible by printing a JSON string to stdout + before exiting. + +- ``A variable 'irules'`` is a list defined with two irules => ‘irule1’ + and irule2’ +- ``name: ADD iRules`` is a user defined description that will display + in the terminal output. +- ``bigip_irule:`` tells the task which module to use. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with +- The ``module: ltm`` paramters tells the module which BIG-IP + module(ltm) the iRule is for +- The ``name: "{{item}}"`` parameter tells the module to create an + iRule with the name ‘irule1’ and ‘irule2’ +- The ``content: "{{lookup('file','{{item}}')}}"`` parameter tells the + module what content to add to the iRule using the `lookup + plugin `__ +- The ``validate_certs: "no"`` parameter tells the module to not + validate SSL certificates. This is just used for demonstration + purposes since this is a lab. +- ``loop:`` tells the task to loop over the provided list. The list in + this case is the list of iRules. + +Do not exit the file yet. + +Step 5 +------ + +Next, append the ``task`` to above playbook. This task will use the +``bigip_virtual_server`` to add attach the iRules to a Virtual Server on +the BIG-IP. + +.. code-block:: yaml + + - name: ATTACH iRules TO VIRTUAL SERVER + bigip_virtual_server: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + name: "vip" + irules: "{{irules}}" + +- ``irules: "{{irules}}`` is a list of irules to be attached to the + virtual server ‘irule1’ and ‘irule2’ + +Details of `BIG-IP virtual_Server +module `__ +or reference :download:`bigip-virtual-server.yml <./bigip-virtual-server.yml>` + +Save the file and exit out of editor. + +Step 6 +------ + +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-irule.yml + +Playbook Output +=============== + +.. code-block:: yaml + + [centos@ansible]$ ansible-playbook bigip-irule.yml + + PLAY [BIG-IP SETUP] ********************************************************************************************************************************* + + TASK [ADD iRules] ********************************************************************************************************************************* + changed: [f5] => (item=irule1) + changed: [f5] => (item=irule2) + + TASK [ATTACH iRules TO VIRTUAL SERVER] ********************************************************************************************************************** + changed: [f5] + + PLAY RECAP ********************************************************************************************************************************* + f5 : ok=2 changed=2 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-irule.yml <./bigip-irule.yml>`. + +Verifying the Solution +====================== + +To see the configured **iRules and Virtual Server**, login to the F5 +load balancer with your web browser. + + Grab the IP information for the F5 load balancer from the + ``/home/studentX/networking_workshop/lab_inventory/hosts`` file, and + type it in like so: https://X.X.X.X:8443/ + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor** defaults to ansible + +The list of iRules can be found by navigating the menu on the left. +Click on Local Traffic-> iRules -> iRules List. + +To view the Virtual Server click on Local Traffic-> Virtual Servers, +click on the Virtual Server then click on the ‘resoruces’ tab and view +the iRules attached to the Virtual Server |irules| + +You have finished this exercise. + +.. |irules| image:: bigip-irule.png diff --git a/docs/class14/module1/1.7-save-running-config.rst b/docs/class14/module1/1.7-save-running-config.rst new file mode 100644 index 00000000..7bafa604 --- /dev/null +++ b/docs/class14/module1/1.7-save-running-config.rst @@ -0,0 +1,138 @@ +.. _1.7-save-running-config: + +Exercise 1.7: Using the bigip_config module +########################################### + +Objective +========= + +Demonstrate use of the `BIG-IP config +module `__ +to save the running configuration to disk + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-config.yml``. + +.. + + The Ansible node is equipped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 2: +------- + +Ansible playbooks are **YAML** files. YAML is a structured encoding +format that is also extremely human readable (unlike it’s subset - the +JSON format). + +Enter the following play definition into ``bigip-config.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: no`` disables facts gathering. We are not using any + fact variables for this playbook. + +Do not exit the editor yet. + +Step 3 +------ + +Next, add the ``task``. This task will use the ``bigip-config`` to save +the running configuration to disk + +.. code-block:: yaml + + tasks: + + - name: SAVE RUNNING CONFIG ON BIG-IP + bigip_config: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: no + save: yes + +.. + + A play is a list of tasks. Tasks and modules have a 1:1 correlation. + Ansible modules are reusable, standalone scripts that can be used by + the Ansible API, or by the ansible or ansible-playbook programs. They + return information to ansible by printing a JSON string to stdout + before exiting. + +- ``name: SAVE RUNNING CONFIG ON BIG-IP`` is a user defined description + that will display in the terminal output. +- ``bigip_config:`` tells the task which module to use. +- The ``server: "{{private_ip}}"`` parameter tells the module to + connect to the F5 BIG-IP IP address, which is stored as a variable + ``private_ip`` in inventory +- The ``provider:`` parameter is a group of connection details for the + BIG-IP. +- The ``user: "{{ansible_user}}"`` parameter tells the module the + username to login to the F5 BIG-IP device with +- The ``password: "{{ansible_ssh_pass}}"`` parameter tells the module + the password to login to the F5 BIG-IP device with +- The ``server_port: 8443`` parameter tells the module the port to + connect to the F5 BIG-IP device with +- The ``save: "yes""`` parameter tells the module to save the + running-config to startup-config. This operation is performed after + any changes are made to the current running config. If no changes are + made, the configuration is + still saved to the startup config. This option will always cause the + module to return changed +- The ``validate_certs: "no"`` parameter tells the module to not + validate SSL certificates. This is just used for demonstration + purposes since this is a lab. + +Save File and exit out of editor. + +Step 4 +------ + +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-config.yml + +Playbook Output +=============== + +.. code-block:: yaml + + [centos@ansible]$ ansible-playbook bigip-config.yml + + PLAY [BIG-IP SETUP] ************************************************************************************************************************ + + TASK [SAVE RUNNING CONFIG ON BIG-IP] ************************************************************************************************************************ + changed: [f5] + + PLAY RECAP ************************************************************************************************************* + f5 : ok=1 changed=1 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-config.yml <./bigip-config.yml>`. + +You have finished this exercise. diff --git a/docs/class14/module1/animation.gif b/docs/class14/module1/animation.gif new file mode 100644 index 00000000..62472b42 Binary files /dev/null and b/docs/class14/module1/animation.gif differ diff --git a/docs/class14/module1/apptest.png b/docs/class14/module1/apptest.png new file mode 100644 index 00000000..15f3b589 Binary files /dev/null and b/docs/class14/module1/apptest.png differ diff --git a/docs/class14/module1/bigip-config.yml b/docs/class14/module1/bigip-config.yml new file mode 100644 index 00000000..83e4021e --- /dev/null +++ b/docs/class14/module1/bigip-config.yml @@ -0,0 +1,17 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: SAVE RUNNING CONFIG ON BIG-IP + bigip_config: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + save: true diff --git a/docs/class14/module1/bigip-facts.yml b/docs/class14/module1/bigip-facts.yml new file mode 100755 index 00000000..a9bb7ea8 --- /dev/null +++ b/docs/class14/module1/bigip-facts.yml @@ -0,0 +1,30 @@ +--- +- name: GRAB F5 FACTS + hosts: f5 + connection: local + gather_facts: false + + tasks: + - name: COLLECT BIG-IP FACTS + bigip_device_info: + gather_subset: + - system-info + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + register: device_facts + + - name: DISPLAY COMPLETE BIG-IP SYSTEM INFORMATION + debug: + var: device_facts + + - name: DISPLAY ONLY THE MAC ADDRESS + debug: + var: device_facts['system_info']['base_mac_address'] + + - name: DISPLAY ONLY THE VERSION + debug: + var: device_facts['system_info']['product_version'] diff --git a/docs/class14/module1/bigip-irule.png b/docs/class14/module1/bigip-irule.png new file mode 100644 index 00000000..971844b2 Binary files /dev/null and b/docs/class14/module1/bigip-irule.png differ diff --git a/docs/class14/module1/bigip-irule.yml b/docs/class14/module1/bigip-irule.yml new file mode 100644 index 00000000..4c5d79d5 --- /dev/null +++ b/docs/class14/module1/bigip-irule.yml @@ -0,0 +1,31 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + vars: + irules: ['irule1', 'irule2'] + tasks: + - name: ADD iRules + bigip_irule: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + module: "ltm" + name: "{{item}}" + content: "{{lookup('file','{{item}}')}}" + with_items: "{{irules}}" + + - name: ATTACH iRules TO VIRTUAL SERVER + bigip_virtual_server: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + name: "vip" + irules: "{{irules}}" diff --git a/docs/class14/module1/bigip-node.yml b/docs/class14/module1/bigip-node.yml new file mode 100755 index 00000000..84bcffcc --- /dev/null +++ b/docs/class14/module1/bigip-node.yml @@ -0,0 +1,19 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: CREATE NODES + bigip_node: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + host: "{{hostvars[item].ansible_host}}" + name: "{{hostvars[item].inventory_hostname}}" + loop: "{{ groups['webservers'] }}" diff --git a/docs/class14/module1/bigip-pool-members.yml b/docs/class14/module1/bigip-pool-members.yml new file mode 100755 index 00000000..564b3131 --- /dev/null +++ b/docs/class14/module1/bigip-pool-members.yml @@ -0,0 +1,22 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: ADD POOL MEMBERS + bigip_pool_member: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + state: "present" + name: "{{hostvars[item].inventory_hostname}}" + host: "{{hostvars[item].ansible_host}}" + port: "80" + pool: "http_pool" + loop: "{{ groups['webservers'] }}" diff --git a/docs/class14/module1/bigip-pool.yml b/docs/class14/module1/bigip-pool.yml new file mode 100755 index 00000000..349a9b9a --- /dev/null +++ b/docs/class14/module1/bigip-pool.yml @@ -0,0 +1,20 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: CREATE POOL + bigip_pool: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + name: "http_pool" + lb_method: "round-robin" + monitors: "/Common/http" + monitor_type: "and_list" diff --git a/docs/class14/module1/bigip-virtual-server.yml b/docs/class14/module1/bigip-virtual-server.yml new file mode 100755 index 00000000..fd98944f --- /dev/null +++ b/docs/class14/module1/bigip-virtual-server.yml @@ -0,0 +1,23 @@ +--- +- name: BIG-IP SETUP + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: ADD VIRTUAL SERVER + bigip_virtual_server: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: false + name: "vip" + destination: "{{destination_ip}}" + port: "443" + enabled_vlans: "all" + all_profiles: ['http', 'clientssl', 'oneconnect'] + pool: "http_pool" + snat: "Automap" diff --git a/docs/class14/module1/display-pool-members.yml b/docs/class14/module1/display-pool-members.yml new file mode 100644 index 00000000..c22350fe --- /dev/null +++ b/docs/class14/module1/display-pool-members.yml @@ -0,0 +1,28 @@ +--- +- name: "List pool members" + hosts: lb + gather_facts: false + connection: local + + tasks: + + - name: Query BIG-IP facts + bigip_device_info: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: "no" + gather_subset: + - ltm-pools + register: bigip_device_facts + + - name: "View complete output" + debug: "msg={{bigip_device_facts}}" + + - name: "Show members belonging to pool" + debug: "msg={{item}}" + loop: "{{bigip_device_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='http_pool'].members[*].name[]" diff --git a/docs/class14/module1/f5vip.png b/docs/class14/module1/f5vip.png new file mode 100644 index 00000000..52506e68 Binary files /dev/null and b/docs/class14/module1/f5vip.png differ diff --git a/docs/class14/module1/irule1 b/docs/class14/module1/irule1 new file mode 100644 index 00000000..0d869f08 --- /dev/null +++ b/docs/class14/module1/irule1 @@ -0,0 +1,3 @@ +when HTTP_REQUEST { + log local0. "Accessing iRule1" + } diff --git a/docs/class14/module1/irule2 b/docs/class14/module1/irule2 new file mode 100644 index 00000000..0c6d2484 --- /dev/null +++ b/docs/class14/module1/irule2 @@ -0,0 +1,3 @@ +when HTTP_REQUEST { + log local0. "Accessing iRule2" + } diff --git a/docs/class14/module1/labguide.png b/docs/class14/module1/labguide.png new file mode 100644 index 00000000..d06589b5 Binary files /dev/null and b/docs/class14/module1/labguide.png differ diff --git a/docs/class14/module1/module1.rst b/docs/class14/module1/module1.rst new file mode 100644 index 00000000..1ec13394 --- /dev/null +++ b/docs/class14/module1/module1.rst @@ -0,0 +1,15 @@ +Section 1 - Ansible F5 Basic Exercises +====================================== + +.. toctree:: + :maxdepth: 1 + + 0.0-getting-started + 1.0-explore + 1.1-get-facts + 1.2-add-node + 1.3-add-pool + 1.4-add-pool-members + 1.5-add-virtual-server + 1.6-add-irules + 1.7-save-running-config diff --git a/docs/class14/module1/new_file.png b/docs/class14/module1/new_file.png new file mode 100644 index 00000000..3d2d24e8 Binary files /dev/null and b/docs/class14/module1/new_file.png differ diff --git a/docs/class14/module1/nginx-install.yml b/docs/class14/module1/nginx-install.yml new file mode 100644 index 00000000..81a5041f --- /dev/null +++ b/docs/class14/module1/nginx-install.yml @@ -0,0 +1,29 @@ +--- +- hosts: webservers + become: true + roles: + - role: nginxinc.nginx + vars: + nginx_http_template_enable: true + nginx_http_template: + default: + template_file: http/default.conf.j2 + conf_file_name: default.conf + conf_file_location: /etc/nginx/conf.d/ + servers: + server1: + listen: + listen_localhost: + # ip: 0.0.0.0 + port: 80 + server_name: localhost + error_page: /usr/share/nginx/html + autoindex: false + web_server: + locations: + default: + location: / + html_file_location: /usr/share/nginx/html + html_file_name: index.html + autoindex: false + http_demo_conf: false diff --git a/docs/class14/module1/nodes.png b/docs/class14/module1/nodes.png new file mode 100644 index 00000000..0548385a Binary files /dev/null and b/docs/class14/module1/nodes.png differ diff --git a/docs/class14/module1/pool.png b/docs/class14/module1/pool.png new file mode 100644 index 00000000..6ddd10f6 Binary files /dev/null and b/docs/class14/module1/pool.png differ diff --git a/docs/class14/module1/poolmembers.png b/docs/class14/module1/poolmembers.png new file mode 100644 index 00000000..a2350983 Binary files /dev/null and b/docs/class14/module1/poolmembers.png differ diff --git a/docs/class14/module1/terminal.png b/docs/class14/module1/terminal.png new file mode 100644 index 00000000..3fa40424 Binary files /dev/null and b/docs/class14/module1/terminal.png differ diff --git a/docs/class14/module1/vscode_access.png b/docs/class14/module1/vscode_access.png new file mode 100644 index 00000000..228b743d Binary files /dev/null and b/docs/class14/module1/vscode_access.png differ diff --git a/docs/class14/module1/vscode_pane.png b/docs/class14/module1/vscode_pane.png new file mode 100644 index 00000000..53134567 Binary files /dev/null and b/docs/class14/module1/vscode_pane.png differ diff --git a/docs/class14/module2/2.0-disable-pool-member.rst b/docs/class14/module2/2.0-disable-pool-member.rst new file mode 100644 index 00000000..56b9281e --- /dev/null +++ b/docs/class14/module2/2.0-disable-pool-member.rst @@ -0,0 +1,253 @@ +.. _2.0-disable-pool-members: + +Exercise 2.0: Disabling a pool member +###################################### + +Objective +========= + +This time we are going to disable a pool member from the pool. +The build syntax will demonstrate the removal of a node +from the pool. + +Build a Playbook that: + +- Retrieve Facts from BIG-IP for the pools present on the BIG-IP (in our + example only one pool is present) +- Display pools available +- Store the pool name as a fact +- Display all the pool members that belong to the + pool +- Prompt the user to disable a particular member or disable all members of the pool +- Force the appropriate pool members offline + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``disable-pool-member.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 ``disable-pool-member.yml``: + +.. code-block:: yaml + + --- + - name: "Disabling a pool member" + hosts: lb + gather_facts: false + connection: local + +Step 3 +------ + +Add a tasks section and then set a fact for the provider. Once you set +the provider you can re-use this key in future tasks instead of giving +the server/user/password/server_port and validate_certs info to each +task. + +.. 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 a task to Retrieve Facts from BIG-IP for the subset ``ltm-pools`` + +.. code-block:: yaml + + - name: Query BIG-IP facts + bigip_device_info: + provider: "{{provider}}" + gather_subset: + - ltm-pools + register: bigip_facts + +You DO NOT need to pass the server_ip/user/password etc. for each module +going forward. + +Step 5 +------ + +Deploy ``ansible-playbook disable-pool-member.yml -vvvv`` and watch the outcome. + +The ``-vvvv`` creates extra verbose and makes that you sew more output when the ansible playbook gets deployed + +Step 6 +------ + +Next, add a task to Display the pool information to the terminal window + +.. code-block:: yaml + + - name: Display Pools available + debug: "msg={{item.name}}" + loop: "{{bigip_facts.ltm_pools}}" + loop_control: + label: "{{item.name}}" + +Repeat Step 5 by deploying the Ansible playbook. + +Step 7 +------ + +Next, add a task to Store the pool name as a fact + +.. code-block:: yaml + + - name: Store pool name in a variable + set_fact: + pool_name: "{{item.name}}" + loop: "{{bigip_facts.ltm_pools}}" + no_log: true + +Repeat Step 5 by deploying the Ansible playbook. + +Step 8 +------ + +Next, add a task to Display members belonging to the pool + +.. code-block:: yaml + + - name: "Show members belonging to pool {{pool_name}}" + debug: "msg={{item}}" + loop: "{{bigip_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='{{pool_name}}'].members[*].name[]" + +Step 9 +------ + +Next, add a task which will ask the user to enter one of two options: + +- a Host:Port to disable a particular member +- ‘all’ to disable all members + +.. code-block:: yaml + + - pause: + prompt: "To disable a particular member enter member with format member_name:port \nTo disable all members of the pool enter 'all'" + register: member_name + +Step 10 +------- + +Next, add a task which will Read the prompt information and disable all members or a single member based on the input from the user + +.. code-block:: yaml + + - name: Disable ALL pool members + bigip_pool_member: + provider: "{{provider}}" + state: "forced_offline" + name: "{{item.split(':')[0]}}" + pool: "{{pool_name}}" + port: "{{item.split(':')[1]}}" + host: "{{hostvars[item.split(':')[0]].ansible_host}}" + loop: "{{bigip_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='{{pool_name}}'].members[*].name[]" + when: '"all" in member_name.user_input' + + - name: Disable pool member {{member_name.user_input}} + bigip_pool_member: + provider: "{{provider}}" + state: "forced_offline" + name: "{{member_name.user_input.split(':')[0]}}" + pool: "{{pool_name}}" + port: "{{member_name.user_input.split(':')[1]}}" + host: "{{hostvars[member_name.user_input.split(':')[0]].ansible_host}}" + when: '"all" not in member_name.user_input' + + +Step 10 +------- + +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 disable-pool-member.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook disable-pool-member.yml + + PLAY [Disabling a pool member] ****************************************************************************************************************************** + + TASK [Setup provider] ******************************************************************************************************************************* + ok: [f5] + + TASK [Query BIG-IP facts] *********************************************************************************************************************************** + changed: [f5] + + TASK [Display Pools available] ****************************************************************************************************************************** + ok: [f5] => (item=http_pool) => { + "msg": "http_pool" + } + + TASK [Store pool name in a variable] ************************************************************************************************************************ + ok: [f5] => (item=None) + ok: [f5] + + TASK [Show members belonging to pool http_pool] ************************************************************************************************************* + ok: [f5] => (item=host1:80) => { + "msg": "host1:80" + } + ok: [f5] => (item=host2:80) => { + "msg": "host2:80" + } + + TASK [pause] ************************************************************************************************************ + [pause] + To disable a particular member enter member with format member_name:port + To disable all members of the pool enter 'all': + host1:80 + + TASK [Disable ALL pool members] ************************************************************************************************************************ + skipping: [f5] => (item=host1:80) + skipping: [f5] => (item=host2:80) + + TASK [Disable pool member host1:80] ************************************************************************************************************************* + changed: [f5] + + PLAY RECAP ************************************************************************************************************** + f5 : ok=7 changed=2 unreachable=0 failed=0 + +Solution +======== + +The solution will be provided by the instructor if you are stuck. The +GUI should show something similar to the following with a black diamond +indicating the specified node was forced offline. + +.. figure:: f5bigip-gui.png + :alt: f5bigip-gui + + +You have finished this exercise. diff --git a/docs/class14/module2/2.1-delete-configuration.rst b/docs/class14/module2/2.1-delete-configuration.rst new file mode 100644 index 00000000..b4bd5587 --- /dev/null +++ b/docs/class14/module2/2.1-delete-configuration.rst @@ -0,0 +1,180 @@ +.. _2.1-delete-configuration: + +Exercise 2.1: Using a combination of modules to delete configuration on the BIG-IP +################################################################################## + +Objective +========= + +Demonstrate use of the different modules to delete the configuration +(Nodes/Pool/Virtual Server) on the BIG-IP. # Guide + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``bigip-delete-configuration.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-delete-configuration.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: no`` 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 first ``task`` using the +`bigip_virtual_server `__. +This task will be identical to :ref:`Exercise 1.5 - Adding a virtual +server <1.5-add-virtual-server>` with an additional +**state** parameter. The ``state: absent`` will remove the configuration +from the F5 BIG-IP load balancer. + +.. code-block:: yaml + + - name: DELETE VIRTUAL SERVER + bigip_virtual_server: + provider: "{{provider}}" + name: "vip" + state: absent + +- ``state: absent`` is a parameter that tells the module to delete the + configuration + +Step 5 +------ + +Next, add the second ``task`` using the +`bigip_pool `__. +This task will be identical to :ref:`Exercise 1.3 - Adding a load balancing +pool <1.3-add-pool>` with an additional **state** +parameter set to ``absent``. + + +.. code-block:: yaml + + - name: DELETE POOL + bigip_pool: + provider: "{{provider}}" + name: "http_pool" + state: absent + +Step 6 +------ + +Finally, add the last ``task`` using the +`bigip_node `__. +This task will be identical to :ref:`Exercise 1.2 - Adding nodes to F5 +BIG-IP <1.2-add-node>` with an additional **state** parameter set to +``absent``. + +.. code-block:: yaml + + - name: DELETE NODES + bigip_node: + provider: "{{provider}}" + name: "{{hostvars[item].inventory_hostname}}" + state: absent + loop: "{{ groups['webservers'] }}" + +The above playbook will delete the virtual server, then the pool and +then the nodes configured in previous exercises. + +Step 7 +------ + +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-delete-configuration.yml + +Playbook Output +=============== + +.. code-block:: shell-session + + [centos@ansible]$ ansible-playbook bigip-delete-configuration.yml + + PLAY [BIG-IP TEARDOWN] ************************************************************************************************************************************** + + TASK [Setup provider] *************************************************************************************************************************************** + ok: [f5] + + TASK [DELETE VIRTUAL SERVER] ******************************************************************************************************************************** + changed: [f5] + + TASK [DELETE POOL] ********************************************************************************************************************************* + changed: [f5] + + TASK [DELETE NODES] ************************************************************************************************************************************* + changed: [f5] => (item=host1) + changed: [f5] => (item=host2) + + PLAY RECAP ************************************************************************************************************************************** + f5 : ok=4 changed=3 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`bigip-delete-configuration.yml <./bigip-delete-configuration.yml>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. + +Login information for the BIG-IP: - username: admin - password: +**provided by instructor defaults to ansible** + +Navigate the menu on the left and view that the configuration has been +deleted. + +- Check: Local Traffic Manager -> Virtual Server +- Check: Local Traffic Manager -> Pool +- Check: Local Traffic Manager -> Node + +All configured objetcs are removed and the BIG-IP is 'empty'. + +You have finished this exercise. diff --git a/docs/class14/module2/2.2-error-handling.rst b/docs/class14/module2/2.2-error-handling.rst new file mode 100644 index 00000000..a2864444 --- /dev/null +++ b/docs/class14/module2/2.2-error-handling.rst @@ -0,0 +1,334 @@ +.. _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 effort you have been saved from doing is that you don't need to clean the config on 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. diff --git a/docs/class14/module2/bigip-delete-configuration.yml b/docs/class14/module2/bigip-delete-configuration.yml new file mode 100644 index 00000000..4b829ed7 --- /dev/null +++ b/docs/class14/module2/bigip-delete-configuration.yml @@ -0,0 +1,34 @@ +--- +- name: BIG-IP TEARDOWN + 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: 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'] }}" diff --git a/docs/class14/module2/bigip-error-handling.yml b/docs/class14/module2/bigip-error-handling.yml new file mode 100644 index 00000000..5ee299b8 --- /dev/null +++ b/docs/class14/module2/bigip-error-handling.yml @@ -0,0 +1,79 @@ +--- +- 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: true diff --git a/docs/class14/module2/disable-pool-member.yml b/docs/class14/module2/disable-pool-member.yml new file mode 100644 index 00000000..a1d29eee --- /dev/null +++ b/docs/class14/module2/disable-pool-member.yml @@ -0,0 +1,66 @@ +--- +- name: "Disabling a pool member" + hosts: lb + gather_facts: false + connection: local + tasks: + - name: Setup provider + set_fact: + provider: + server: "{{private_ip}}" + user: "{{ansible_user}}" + password: "{{ansible_ssh_pass}}" + server_port: 8443 + validate_certs: "no" + + - name: Query BIG-IP facts + bigip_device_info: + provider: "{{provider}}" + gather_subset: + - ltm-pools + register: bigip_facts + + - name: Display Pools available + debug: "msg={{item.name}}" + loop: "{{bigip_facts.ltm_pools}}" + loop_control: + label: "{{item.name}}" + + - name: Store pool name in a variable + set_fact: + pool_name: "{{item.name}}" + loop: "{{bigip_facts.ltm_pools}}" + no_log: true + + - name: "Show members belonging to pool {{pool_name}}" + debug: "msg={{item}}" + loop: "{{bigip_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='{{pool_name}}'].members[*].name[]" + + - pause: + prompt: "To disable a particular member enter member with format member_name:port \nTo disable all members of the pool enter 'all'" + register: member_name + + - name: Disable ALL pool members + bigip_pool_member: + provider: "{{provider}}" + state: "forced_offline" + name: "{{item.split(':')[0]}}" + pool: "{{pool_name}}" + port: "{{item.split(':')[1]}}" + host: "{{hostvars[item.split(':')[0]].ansible_host}}" + loop: "{{bigip_facts.ltm_pools | json_query(query_string)}}" + vars: + query_string: "[?name=='{{pool_name}}'].members[*].name[]" + when: '"all" in member_name.user_input' + + - name: Disable pool member {{member_name.user_input}} + bigip_pool_member: + provider: "{{provider}}" + state: "forced_offline" + name: "{{member_name.user_input.split(':')[0]}}" + pool: "{{pool_name}}" + port: "{{member_name.user_input.split(':')[1]}}" + host: "{{hostvars[member_name.user_input.split(':')[0]].ansible_host}}" + when: '"all" not in member_name.user_input' diff --git a/docs/class14/module2/error.png b/docs/class14/module2/error.png new file mode 100644 index 00000000..4777900f Binary files /dev/null and b/docs/class14/module2/error.png differ diff --git a/docs/class14/module2/f5bigip-gui.png b/docs/class14/module2/f5bigip-gui.png new file mode 100644 index 00000000..7a384147 Binary files /dev/null and b/docs/class14/module2/f5bigip-gui.png differ diff --git a/docs/class14/module2/module2.rst b/docs/class14/module2/module2.rst new file mode 100644 index 00000000..869e252f --- /dev/null +++ b/docs/class14/module2/module2.rst @@ -0,0 +1,10 @@ +Section 2 - Ansible F5 Operational/Advanced Exercises +===================================================== + +.. toctree:: + :maxdepth: 1 + :glob: + + 2.0-disable-pool-member + 2.1-delete-configuration + 2.2-error-handling diff --git a/docs/class14/module3/3.0-as3-intro/3.0-as3-intro.rst b/docs/class14/module3/3.0-as3-intro/3.0-as3-intro.rst new file mode 100644 index 00000000..3568d251 --- /dev/null +++ b/docs/class14/module3/3.0-as3-intro/3.0-as3-intro.rst @@ -0,0 +1,340 @@ +.. _3.0-as3-intro: + +Exercise 3.0: Introduction to AS3 +################################## + +Objective +========= + +Demonstrate building a virtual server (exactly like the Section 1 +Ansible F5 Exercises) with F5 AS3 + +- Learn about AS3 (`Application Services 3 + Extension `__) + declarative model. It is not the intention of this exercise to learn + AS3 thoroughly, but just give some introduction to the concept and + show how it easily integrates with Ansible Playbooks. +- Learn about the `set_fact + module `__ +- Learn about the `uri + module `__ + +Guide +===== + +Make sure the BIG-IP configuration is clean, run exercise 1.6-delete-configuration before proceeding +---------------------------------------------------------------------------------------------------- + +Step 1: +------- + +Make sure the F5 BIG-IP has AS3 enabled. + +1. Login to the F5 BIG-IP through your web browser. +2. Click on the iApps button on the lefthand menu. +3. Click the ``Package Management LX`` Link +4. Make sure that ``f5-appsvcs`` is installed. + +If this is not working please ask your instructor for help. + +.. figure:: f5-appsvcs.png + :alt: f5 appsvcs + + f5 appssvcs + +Step 2: +------- + +Before starting to build a Playbook, its important to understand how AS3 +works. AS3 requires a JSON template to be handed as an API call to F5 +BIG-IP. **The templates are provided** for this exercise. You do not +need to fully understand every parameter, or create these templates from +scratch. There are two parts-> + +1. ``tenant_base.j2`` + +.. code-block:: jinja + + { + "class": "AS3", + "action": "deploy", + "persist": true, + "declaration": { + "class": "ADC", + "schemaVersion": "3.2.0", + "id": "testid", + "label": "test-label", + "remark": "test-remark", + "WorkshopExample":{ + "class": "Tenant", + {{ as3_app_body }} + } + } + } + +``tenant_base`` is a standard template that F5 Networks will provide to +their customers. The important parts to understand are: + +- ``"WorkshopExample": {`` - this is the name of our Tenant. The AS3 + will create a tenant for this particular WebApp. A WebApp in this + case is a virtual server that load balances between our two web + servers. +- ``"class": "Tenant",`` - this indicates that ``WorkshopExample`` is a + Tenant. +- ``as3_app_body`` - this is a variable that will point to the second + jinja2 template which is the actual WebApp. + +-------------- + +2. ``as3_template.j2`` + +.. code-block:: jinja + + "web_app": { + "class": "Application", + "template": "http", + "serviceMain": { + "class": "Service_HTTP", + "virtualAddresses": [ + "{{vs_private_ip}}" + ], + "pool": "app_pool" + }, + "app_pool": { + "class": "Pool", + "monitors": [ + "http" + ], + "members": [ + { + "servicePort": 443, + "serverAddresses": [ + {% set comma = joiner(",") %} + {% for mem in pool_members %} + {{comma()}} "{{ hostvars[mem]['ansible_host'] }}" + {% endfor %} + + ] + } + ] + } + } + +This template is a JSON representation of the Web Application. The +important parts to note are: + +- There is a virtual server named ``serviceMain``. + + - The template can use variables just like tasks do in previous + exercises. In this case the virtual IP address is the private_ip + from our inventory. + +- There is a Pool named ``app_pool`` + + - The jinja2 template can use a loop to grab all the pool members + (which points to our web servers group that will be elaborated on + below). + +**In Summary** the ``tenant_base.j2`` and ``as3_template.j2`` create one +single JSON payload that represents a Web Application. We will build a +Playbook that will send this JSON payload to a F5 BIG-IP. + +**COPY THESE TEMPLATES TO YOUR WORKING DIRECTORY** + +.. code-block:: shell-session + + mkdir j2 + cp ~/networking-workshop/3.0-as3-intro/j2/* j2/ + +Step 3: +------- + +Use VS Code Explorer to create a new file called ``as3.yml``: + +.. + + The Ansible node is equiped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 4: +------- + +Enter the following play definition into ``as3.yml``: + +.. code-block:: yaml + + --- + - name: LINKLIGHT AS3 + hosts: lb + connection: local + gather_facts: false + + vars: + pool_members: "{{ groups['webservers'] }}" + +- The ``---`` at the top of the file indicates that this is a YAML + file. +- The ``hosts: lb``, indicates the play is run only on the lb group. + Technically there only one F5 device but if there were multiple they + would be configured simultaneously. +- ``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. + +This section from above… + +.. code-block:: yaml + + vars: + pool_members: "{{ groups['webservers'] }}" + +…sets a variable named ``pool_members``, to the webservers group. There +are two webservers on the workbench, ``host1`` and ``host2``. This means +that the ``pool_members`` variable refers to a list of two webservers. + +Step 5 +------ + +**Append** the following to the as3.yml Playbook. + +.. code-block:: yaml + + tasks: + + - name: CREATE AS3 JSON BODY + set_fact: + as3_app_body: "{{ lookup('template', 'j2/as3_template.j2', split_lines=False) }}" + +The module `set_fact +module `__ +allows a Playbook to create (or override) a variable as a task within a +Play. This can be used to create new facts on the fly dynamically that +didn’t exist until that point in the Play. In this case the `template +lookup +plugin `__ +is being used. This task 1. renders the j2/as3_template.j2 jinja +template that is provided. 2. creates a new fact named ``as3_app_body`` +that is just JSON text. + +Step 6 +------ + +**Append** the following to the as3.yml Playbook. This task uses the uri +module which is used to interact with HTTP and HTTPS web services and +supports Digest, Basic and WSSE HTTP authentication mechanisms. This +module is extremely common and very easy to use. The workshop itself +(the Playbooks that provisioned the workbenches) uses the uri module to +configure and license Red Hat Ansible Tower. + +.. code-block:: yaml + + - name: PUSH AS3 + uri: + url: "https://{{ private_ip }}:8443/mgmt/shared/appsvcs/declare" + method: POST + body: "{{ lookup('template','j2/tenant_base.j2', split_lines=False) }}" + status_code: 200 + timeout: 300 + body_format: json + force_basic_auth: yes + user: "{{ ansible_user }}" + password: "{{ ansible_ssh_pass }}" + validate_certs: no + delegate_to: localhost + +Explanation of parameters: + +.. code-block:: html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
parameterexplanation
- name: PUSH AS3human description of Playbook task, prints to terminal window
uri:this task is calling the uri module
url: "https://{{ ansible_host }}:8443/mgmt/shared/appsvcs/declare"webURL (API) for AS3
method: POSTHTTP method of the request, must be uppercase. Module documentation page has list of all options. This could also be a DELETE vs a POST
body: "{{ lookup('template','j2/tenant_base.j2', split_lines=False) }}"This sends the combined template (the tenant_base.j2 which contains as3_template.j2) and is passed as the body for the API request.
status_code: 200A valid, numeric, HTTP status code that signifies success of the request. Can also be comma separated list of status codes. 200 means OK, which is a standard response for successful HTTP requests
+ +The rest of the parameters are for authentication to the F5 BIG-IP and +fairly straight forward (similar to all BIG-IP modules). + +Step 7 +------ + +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 as3.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: yaml + + [centos@ansible ~]$ ansible-playbook as3.yml + + PLAY [Linklight AS3] *********************************************************** + + TASK [Create AS3 JSON Body] **************************************************** + ok: [f5] + + TASK [Push AS3] **************************************************************** + ok: [f5 -> localhost] + + PLAY RECAP ********************************************************************* + f5 : ok=2 changed=0 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`as3.yml <./as3.yml>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. Grab +the IP information for the F5 load balancer from the lab_inventory/hosts +file, and type it in like so: https://X.X.X.X:8443/ + +.. figure:: f5-as3.png + :alt: f5 gui as3 + + f5 gui as3 + +1. Click on the Local Traffic on the lefthand menu +2. Click on Virtual Servers. +3. On the top right, click on the drop down menu titled ``Partition`` + and select WorkshopExample +4. The Virtual Server ``serviceMain`` will be displayed. + +-------------- + +You have finished this exercise. diff --git a/docs/class14/module3/3.0-as3-intro/as3.yml b/docs/class14/module3/3.0-as3-intro/as3.yml new file mode 100644 index 00000000..40514afc --- /dev/null +++ b/docs/class14/module3/3.0-as3-intro/as3.yml @@ -0,0 +1,27 @@ +--- +- name: LINKLIGHT AS3 + hosts: lb + connection: local + gather_facts: false + + vars: + pool_members: "{{ groups['webservers'] }}" + + tasks: + - name: CREATE AS3 JSON BODY + set_fact: + as3_app_body: "{{ lookup('template', 'j2/as3_template.j2', split_lines=False) }}" + + - name: PUSH AS3 + uri: + url: "https://{{ private_ip }}:8443/mgmt/shared/appsvcs/declare" + method: POST + body: "{{ lookup('template','j2/tenant_base.j2', split_lines=False) }}" + status_code: 200 + timeout: 300 + body_format: json + force_basic_auth: true + user: "{{ ansible_user }}" + password: "{{ ansible_ssh_pass }}" + validate_certs: false + delegate_to: localhost diff --git a/docs/class14/module3/3.0-as3-intro/f5-appsvcs.gif b/docs/class14/module3/3.0-as3-intro/f5-appsvcs.gif new file mode 100644 index 00000000..cf3c2333 Binary files /dev/null and b/docs/class14/module3/3.0-as3-intro/f5-appsvcs.gif differ diff --git a/docs/class14/module3/3.0-as3-intro/f5-appsvcs.png b/docs/class14/module3/3.0-as3-intro/f5-appsvcs.png new file mode 100644 index 00000000..000cb96a Binary files /dev/null and b/docs/class14/module3/3.0-as3-intro/f5-appsvcs.png differ diff --git a/docs/class14/module3/3.0-as3-intro/f5-as3.gif b/docs/class14/module3/3.0-as3-intro/f5-as3.gif new file mode 100644 index 00000000..dc331ed4 Binary files /dev/null and b/docs/class14/module3/3.0-as3-intro/f5-as3.gif differ diff --git a/docs/class14/module3/3.0-as3-intro/f5-as3.png b/docs/class14/module3/3.0-as3-intro/f5-as3.png new file mode 100644 index 00000000..88b430fa Binary files /dev/null and b/docs/class14/module3/3.0-as3-intro/f5-as3.png differ diff --git a/docs/class14/module3/3.0-as3-intro/j2/as3_template.j2 b/docs/class14/module3/3.0-as3-intro/j2/as3_template.j2 new file mode 100644 index 00000000..a2ba2f16 --- /dev/null +++ b/docs/class14/module3/3.0-as3-intro/j2/as3_template.j2 @@ -0,0 +1,29 @@ +"web_app": { + "class": "Application", + "template": "http", + "serviceMain": { + "class": "Service_HTTP", + "virtualAddresses": [ + "{{vs_private_ip}}" + ], + "pool": "app_pool" + }, + "app_pool": { + "class": "Pool", + "monitors": [ + "http" + ], + "members": [ + { + "servicePort": 443, + "serverAddresses": [ + {% set comma = joiner(",") %} + {% for mem in pool_members %} + {{comma()}} "{{ hostvars[mem]['ansible_host'] }}" + {% endfor %} + + ] + } + ] + } +} diff --git a/docs/class14/module3/3.0-as3-intro/j2/tenant_base.j2 b/docs/class14/module3/3.0-as3-intro/j2/tenant_base.j2 new file mode 100644 index 00000000..ef02ad40 --- /dev/null +++ b/docs/class14/module3/3.0-as3-intro/j2/tenant_base.j2 @@ -0,0 +1,16 @@ +{ + "class": "AS3", + "action": "deploy", + "persist": true, + "declaration": { + "class": "ADC", + "schemaVersion": "3.2.0", + "id": "testid", + "label": "test-label", + "remark": "test-remark", + "WorkshopExample":{ + "class": "Tenant", + {{ as3_app_body }} + } + } +} diff --git a/docs/class14/module3/3.1-as3-change/3.1-as3-change.rst b/docs/class14/module3/3.1-as3-change/3.1-as3-change.rst new file mode 100644 index 00000000..56275c22 --- /dev/null +++ b/docs/class14/module3/3.1-as3-change/3.1-as3-change.rst @@ -0,0 +1,135 @@ +.. _3.1-as3-change: + +Exercise 3.1: Operational Change with AS3 +########################################## + +Objective +========= + +| Demonstrate changing an existing Web Application AS3 template. There + is a problem with the existing template, the serviceMain is showing + red. What is wrong? +| |serviceMain-offline.png| + +Guide +===== + +Step 1: +------- + +Figure out what is wrong. Login to the F5 with your web browser to see +what was configured. + +1. Click on ``ServiceMain`` to see why its down. +2. Look at the ``Availability`` field in the table. + +.. figure:: pool-nodes-down.png + :alt: pool-nodes-down.png + + pool-nodes-down.png + +3. Click on the ``Pools`` under ``Local Traffic`` +4. Click on ``app_pool`` +5. Click on the ``Members`` button + +.. figure:: 443.png + :alt: 443 + + 443 + +The port **443** is incorrect. The two RHEL web servers are only running +on port 80. This is why they are showing down. + +Step 2: +------- + +Using your text editor of choice open the existing jinja template +``as3_template.j2``: + +.. + + ``vim`` and ``nano`` are available on the control node. + The Ansible node is equiped with ``Visual Studio Code`` and can be accessed via UDF ACCESS Methods. + +Step 3: +------- + +Find where the port **443** is and modify it to port **80**. + +The line looks as follows-> + +.. code-block:: jinja + + "servicePort": 443, + +change it to-> + +.. code-block:: jinja + + "servicePort": 80, + +Step 4 +------ + +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 as3.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook as3.yml + + PLAY [Linklight AS3] *********************************************************** + + TASK [Create AS3 JSON Body] **************************************************** + ok: [f5] + + TASK [Push AS3] **************************************************************** + ok: [f5 -> localhost] + + PLAY RECAP ********************************************************************* + f5 : ok=2 changed=0 unreachable=0 failed=0 + +Solution +======== + +The fixed Jinja template is provided here for an Answer key. Click +here: :download:`as3_template.j2 <./j2/as3_template.j2>`. + +Verifying the Solution +====================== + +Login to the F5 with your web browser to see what was configured. Grab +the IP information for the F5 load balancer from the lab_inventory/hosts +file, and type it in like so: https://X.X.X.X:8443/ + +.. figure:: as3-fix.png + :alt: f5 gui as3 + + f5 gui as3 + +1. Click on the Local Traffic on the lefthand menu +2. Click on Virtual Servers. +3. On the top right, click on the drop down menu titled ``Partition`` + and select WorkshopExample +4. The Virtual Server ``serviceMain`` will be displayed. +5. This time it will be Green + (``Available (Enabled) - The virtual server is available``) +6. Verify under ``Pools`` for ``app_pool`` that both web servers are set + to port **80** for their ``service_port`` + +.. note:: + In your environment, go to the f5 component and use the + ``HTTP Virtual Server Test`` access method to test. + +You have finished this exercise. + +.. |serviceMain-offline.png| image:: serviceMain-offline.png diff --git a/docs/class14/module3/3.1-as3-change/443.png b/docs/class14/module3/3.1-as3-change/443.png new file mode 100644 index 00000000..1e0e56e0 Binary files /dev/null and b/docs/class14/module3/3.1-as3-change/443.png differ diff --git a/docs/class14/module3/3.1-as3-change/as3-fix.gif b/docs/class14/module3/3.1-as3-change/as3-fix.gif new file mode 100644 index 00000000..f450fc04 Binary files /dev/null and b/docs/class14/module3/3.1-as3-change/as3-fix.gif differ diff --git a/docs/class14/module3/3.1-as3-change/as3-fix.png b/docs/class14/module3/3.1-as3-change/as3-fix.png new file mode 100644 index 00000000..deb81f6d Binary files /dev/null and b/docs/class14/module3/3.1-as3-change/as3-fix.png differ diff --git a/docs/class14/module3/3.1-as3-change/as3.yml b/docs/class14/module3/3.1-as3-change/as3.yml new file mode 100644 index 00000000..a1e22a9a --- /dev/null +++ b/docs/class14/module3/3.1-as3-change/as3.yml @@ -0,0 +1,25 @@ +--- +- name: LINKLIGHT AS3 + hosts: lb + connection: local + gather_facts: false + vars: + pool_members: "{{ groups['webservers'] }}" + tasks: + - name: CREATE AS3 JSON BODY + set_fact: + as3_app_body: "{{ lookup('template', 'j2/as3_template.j2', split_lines=False) }}" + + - name: PUSH AS3 + uri: + url: "https://{{ private_ip }}:8443/mgmt/shared/appsvcs/declare" + method: POST + body: "{{ lookup('template','j2/tenant_base.j2', split_lines=False) }}" + status_code: 200 + timeout: 300 + body_format: json + force_basic_auth: true + user: "{{ ansible_user }}" + password: "{{ ansible_ssh_pass }}" + validate_certs: false + delegate_to: localhost diff --git a/docs/class14/module3/3.1-as3-change/j2/as3_template.j2 b/docs/class14/module3/3.1-as3-change/j2/as3_template.j2 new file mode 100644 index 00000000..2fee3e8a --- /dev/null +++ b/docs/class14/module3/3.1-as3-change/j2/as3_template.j2 @@ -0,0 +1,29 @@ +"web_app": { + "class": "Application", + "template": "http", + "serviceMain": { + "class": "Service_HTTP", + "virtualAddresses": [ + "{{vs_private_ip}}" + ], + "pool": "app_pool" + }, + "app_pool": { + "class": "Pool", + "monitors": [ + "http" + ], + "members": [ + { + "servicePort": 80, + "serverAddresses": [ + {% set comma = joiner(",") %} + {% for mem in pool_members %} + {{comma()}} "{{ hostvars[mem]['ansible_host'] }}" + {% endfor %} + + ] + } + ] + } +} diff --git a/docs/class14/module3/3.1-as3-change/j2/tenant_base.j2 b/docs/class14/module3/3.1-as3-change/j2/tenant_base.j2 new file mode 100644 index 00000000..ef02ad40 --- /dev/null +++ b/docs/class14/module3/3.1-as3-change/j2/tenant_base.j2 @@ -0,0 +1,16 @@ +{ + "class": "AS3", + "action": "deploy", + "persist": true, + "declaration": { + "class": "ADC", + "schemaVersion": "3.2.0", + "id": "testid", + "label": "test-label", + "remark": "test-remark", + "WorkshopExample":{ + "class": "Tenant", + {{ as3_app_body }} + } + } +} diff --git a/docs/class14/module3/3.1-as3-change/pool-nodes-down.png b/docs/class14/module3/3.1-as3-change/pool-nodes-down.png new file mode 100644 index 00000000..ab79d61a Binary files /dev/null and b/docs/class14/module3/3.1-as3-change/pool-nodes-down.png differ diff --git a/docs/class14/module3/3.1-as3-change/serviceMain-offline.png b/docs/class14/module3/3.1-as3-change/serviceMain-offline.png new file mode 100644 index 00000000..440e1977 Binary files /dev/null and b/docs/class14/module3/3.1-as3-change/serviceMain-offline.png differ diff --git a/docs/class14/module3/3.2-as3-delete/3.2-as3-delete.rst b/docs/class14/module3/3.2-as3-delete/3.2-as3-delete.rst new file mode 100644 index 00000000..5fd0347c --- /dev/null +++ b/docs/class14/module3/3.2-as3-delete/3.2-as3-delete.rst @@ -0,0 +1,109 @@ +.. _3.2-as3-delete: + +Exercise 3.2: Deleting a Web Application +######################################### + +Objective +========= + +Demonstrate deleting a Web Application with AS3 and the uri module. + +Guide +===== + +Step 1: +------- + +Use VS Code Explorer to create a new file called ``delete.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 ``delete.yml``: + +.. code-block:: yaml + + --- + - name: LINKLIGHT AS3 + hosts: lb + connection: local + gather_facts: false + +- The ``---`` at the top of the file indicates that this is a YAML + file. +- The ``hosts: lb``, indicates the play is run only on the lb group. + Technically there only one F5 device but if there were multiple they + would be configured simultaneously. +- ``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 +------ + +**Append** the following to the delete.yml Playbook. + +.. code-block:: yaml + + tasks: + + - name: PUSH AS3 + uri: + url: "https://{{ private_ip }}:8443/mgmt/shared/appsvcs/declare/WorkshopExample" + method: DELETE + status_code: 200 + timeout: 300 + body_format: json + force_basic_auth: yes + user: "{{ ansible_user }}" + password: "{{ ansible_ssh_pass }}" + validate_certs: no + delegate_to: localhost + +There is only three parameters that have changed from the previous +exercise. - ``url`` has changed. Instead of ending with ``declare`` it +now ends with the tenant name, which is ``WorkshopExample``. - +``method`` has changed from POST to DELETE. - ``body`` has been removed. +It is not required since we simply deleting this entire tenant. + +Step 4 +------ + +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 delete.yml + +Playbook Output +=============== + +The output will look as follows. + +.. code-block:: shell-session + + [centos@ansible ~]$ ansible-playbook delete.yml + + PLAY [LINKLIGHT AS3] *********************************************************** + + TASK [PUSH AS3] ******************************************************************************** + ok: [f5 -> localhost] + + PLAY RECAP ******************************************************************************** + f5 : ok=1 changed=0 unreachable=0 failed=0 + +Solution +======== + +The finished Ansible Playbook is provided here for an Answer key. Click +here: :download:`delete.yml <./delete.yml>`. + +Login to the web UI and make sure the ``Partition`` ``WorkshopExample`` is removed. + +– You have finished this exercise. diff --git a/docs/class14/module3/3.2-as3-delete/delete.yml b/docs/class14/module3/3.2-as3-delete/delete.yml new file mode 100644 index 00000000..a7cf3206 --- /dev/null +++ b/docs/class14/module3/3.2-as3-delete/delete.yml @@ -0,0 +1,20 @@ +--- +- name: LINKLIGHT AS3 + hosts: lb + connection: local + gather_facts: false + + tasks: + + - name: PUSH AS3 + uri: + url: "https://{{ private_ip }}:8443/mgmt/shared/appsvcs/declare/WorkshopExample" + method: DELETE + status_code: 200 + timeout: 300 + body_format: json + force_basic_auth: true + user: "{{ ansible_user }}" + password: "{{ ansible_ssh_pass }}" + validate_certs: false + delegate_to: localhost diff --git a/docs/class14/module3/module3.rst b/docs/class14/module3/module3.rst new file mode 100644 index 00000000..a1210030 --- /dev/null +++ b/docs/class14/module3/module3.rst @@ -0,0 +1,10 @@ +Section 3 - Ansible F5 AS3 Exercises +==================================== + +.. toctree:: + :maxdepth: 1 + :glob: + + 3.0-as3-intro/3.0-as3-intro + 3.1-as3-change/3.1-as3-change + 3.2-as3-delete/3.2-as3-delete