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" |
#!/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 }}" |
---
- 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 }}"