The following playbook will create a fully functional VIP; including the supporting monitor, service-group (pool) and servers (nodes) on a netscaler loadbalancer. Additionally, the same playbook has the ability to fully deprovision a VIP and all its supporting artifacts. To do all this I use the native Netscaler Ansible modules. When it comes to using the netscaler_servicegroup module, since the number of servers are not always consistent; I create that task with a Jinja2 template, where its imported back into the play.
netscaler_provision.yaml: a /usr/bin/ansible-playbook -f 10 script text executable, ASCII text
#!/usr/bin/ansible-playbook -f 10 ## Ansible playbook to provision Netscaler VIPs. # Requires: nitrosdk-python # 2018 (v.01) - Playbook from www.davideaves.com --- - name: Netscaler VIP provision hosts: netscaler connection: local gather_facts: False vars: ansible_connection: "local" ansible_python_interpreter: "/usr/bin/env python" state: 'present' lbvip: name: testvip address: 203.0.113.1 server: - name: 'server-1' address: '192.0.2.1' description: 'Ansible Test Server 1' disabled: 'true' - name: 'server-2' address: '192.0.2.2' description: 'Ansible Test Server 2' disabled: 'true' - name: 'server-3' address: '192.0.2.3' description: 'Ansible Test Server 3' disabled: 'true' - name: 'server-4' address: '192.0.2.4' description: 'Ansible Test Server 4' disabled: 'true' - name: 'server-5' address: '192.0.2.5' description: 'Ansible Test Server 5' disabled: 'true' - name: 'server-6' address: '192.0.2.6' description: 'Ansible Test Server 6' disabled: 'true' - name: 'server-7' address: '192.0.2.7' description: 'Ansible Test Server 7' disabled: 'true' - name: 'server-8' address: '192.0.2.8' description: 'Ansible Test Server 8' disabled: 'true' vserver: - port: '80' description: 'Generic service running on 80' type: 'HTTP' method: 'LEASTCONNECTION' persistence: 'SOURCEIP' - port: '443' description: 'Generic service running on 443' type: 'SSL_BRIDGE' method: 'LEASTCONNECTION' persistence: 'SOURCEIP' - port: '8080' description: 'Generic service running on 8080' type: 'HTTP' method: 'LEASTCONNECTION' persistence: 'SOURCEIP' - port: '8081' description: 'Generic service running on 8081' type: 'HTTP' method: 'LEASTCONNECTION' persistence: 'SOURCEIP' - port: '8443' description: 'Generic service running on 8443' type: 'SSL_BRIDGE' method: 'LEASTCONNECTION' persistence: 'SOURCEIP' tasks: - name: Build lbvip and all related componets. block: - local_action: module: netscaler_server nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" name: "{{ item.name }}" ipaddress: "{{ item.address }}" comment: "{{ item.description | default('Ansible Created') }}" disabled: "{{ item.disabled | default('false') }}" with_items: "{{ lbvip.server }}" - local_action: module: netscaler_lb_monitor nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" monitorname: "tcp_{{ lbvip.name }}_{{ item.port }}" type: TCP destport: "{{ item.port }}" with_items: "{{ lbvip.vserver }}" no_log: false - local_action: module: copy content: "{{ lookup('template', 'templates/netscaler_servicegroup.j2') }}" dest: "/tmp/svg_{{ lbvip.name }}_{{ item.port }}.yaml" mode: "0644" with_items: "{{ lbvip.vserver }}" changed_when: false - include_tasks: "/tmp/svg_{{ lbvip.name }}_{{ item.port }}.yaml" with_items: "{{ lbvip.vserver }}" - local_action: module: file state: absent path: "/tmp/svg_{{ lbvip.name }}_{{ item.port }}.yaml" with_items: "{{ lbvip.vserver }}" changed_when: false - local_action: module: netscaler_lb_vserver nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" name: "vs_{{ lbvip.name }}_{{ item.port }}" servicetype: "{{ item.type }}" ipv46: "{{ lbvip.address }}" port: "{{ item.port }}" lbmethod: "{{ item.method | default('LEASTCONNECTION') }}" persistencetype: "{{ item.persistence | default('SOURCEIP') }}" servicegroupbindings: - servicegroupname: "svg_{{ lbvip.name }}_{{ item.port }}" with_items: "{{ lbvip.vserver }}" when: state == "present" - name: Destroy lbvip and all related componets. block: - local_action: module: netscaler_lb_vserver nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" name: "vs_{{ lbvip.name }}_{{ item.port }}" with_items: "{{ lbvip.vserver }}" - local_action: module: netscaler_servicegroup nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" servicegroupname: "svg_{{ lbvip.name }}_{{ item.port }}" with_items: "{{ lbvip.vserver }}" - local_action: module: netscaler_lb_monitor nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" monitorname: "tcp_{{ lbvip.name }}_{{ item.port }}" type: TCP with_items: "{{ lbvip.vserver }}" - local_action: module: netscaler_server nsip: "{{ inventory_hostname }}" nitro_user: "{{ nitro_user | default('nsroot') }}" nitro_pass: "{{ nitro_pass | default('nsroot') }}" nitro_protocol: "https" validate_certs: no state: "{{ state }}" name: "{{ item.name }}" with_items: "{{ lbvip.server }}" when: state == "absent" |
The following is the Jinja2 template that creates the netscaler_servicegroup task. An important thing to note is my use of the RAW block. When the task is created and stored in /tmp it does not contain any account credentials, instead I preserve the variable in the raw to prevent leaking sensitive information to anyone who may be snooping around on the server while the playbook is running.
templates/netscaler_servicegroup.j2: ASCII text, with CRLF line terminators
--- - local_action: module: netscaler_servicegroup nsip: {% raw %}"{{ inventory_hostname }}" {% endraw %} nitro_user: {% raw %}"{{ nitro_user }}" {% endraw %} nitro_pass: {% raw %}"{{ nitro_pass }}" {% endraw %} nitro_protocol: "https" validate_certs: no state: "{{ state | default('present') }}" servicegroupname: "svg_{{ lbvip.name }}_{{ item.port }}" comment: "{{ item.description | default('Ansible Created') }}" servicetype: "{{ item.type }}" servicemembers: {% for i in lbvip.server %} - servername: "{{ i.name }}" port: "{{ item.port }}" {% endfor %} monitorbindings: - monitorname: "tcp_{{ lbvip.name }}_{{ item.port }}" |