├── requirements.txt ├── examples ├── vars │ ├── inventory │ └── examples │ │ ├── add_server.yml │ │ ├── deploy_vip.yml │ │ ├── full_partition.yml │ │ └── deploy_full.yml ├── netscaler_change_server_state.yml ├── netscaler_add_server.yml ├── netscaler_deploy_vip.yml ├── netscaler_deploy_full.yml └── netscaler_examples.md ├── unittests ├── netscaler_save_config_unittest.yml ├── netscaler_facts_unittest.yml ├── netscaler_lbvserver_certkey_unittest.yml ├── netscaler_lbvserver_servicegroup_unittest.yml ├── netscaler_server_unittest.yml ├── netscaler_servicegroup_unittest.yml ├── netscaler_servicegroup_monitor_unittest.yml ├── netscaler_servicegroup_server_unittest.yml ├── netscaler_lbmonitor_unittest.yml └── netscaler_lbvserver_unittest.yml ├── examples.md ├── README.md ├── contributing.md ├── Module_Docs └── netscaler_module_docs.md └── library └── netscaler_save_config.py /requirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /examples/vars/inventory: -------------------------------------------------------------------------------- 1 | [all:vars] 2 | ansible_python_interpreter=python 3 | ansible_user=username 4 | ansible_password=password 5 | 6 | [netscaler] 7 | netscaler1 ansible_host=10.1.1.1 8 | -------------------------------------------------------------------------------- /examples/netscaler_change_server_state.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: PLAY 1 - MANAGE SERVER STATE 4 | hosts: netscaler 5 | connection: local 6 | gather_facts: False 7 | 8 | tasks: 9 | - name: TASK 1 - ENSURE SERVER IS IN DESIRED STATE 10 | netscaler_server: 11 | host: "{{ ansible_host }}" 12 | username: "{{ ansible_user }}" 13 | password: "{{ ansible_password }}" 14 | server_name: "{{ server_name }}" 15 | server_state: "{{ server_state | default('disabled') }}" 16 | -------------------------------------------------------------------------------- /unittests/netscaler_save_config_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: SAVE NETSACLER RUNNING CONFIG - CHANGE 9 | netscaler_save_config: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | 14 | - name: SAVE NETSACLER RUNNING CONFIG NO HOST - FAIL 15 | netscaler_save_config: 16 | username: "{{ username }}" 17 | password: "{{ password }}" 18 | ignore_errors: true 19 | -------------------------------------------------------------------------------- /examples/vars/examples/add_server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | servers: 4 | - name: "prod_rhel_03" 5 | ip_address: "10.10.10.23" 6 | comment: "Intranet Server" 7 | - name: "dr_rhel_03" 8 | ip_address: "10.10.20.23" 9 | comment: "Backup Intranet Server" 10 | bindings: 11 | servicegroup_to_servers: 12 | - servicegroup_name: "svcgrp_intranet_https" 13 | server_name: "prod_rhel_03" 14 | port: 443 15 | - servicegroup_name: "svcgrp_backup_intranet_https" 16 | server_name: "dr_rhel_03" 17 | port: 443 18 | - servicegroup_name: "svcgrp_intranet_http" 19 | server_name: "prod_rhel_03" 20 | port: 80 21 | 22 | -------------------------------------------------------------------------------- /examples/vars/examples/deploy_vip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | service_groups: 4 | - name: "svcgrp_intranet_http" 5 | service_type: "HTTP" 6 | comment: "Intranet HTTP Service Group" 7 | lb_vservers: 8 | - name: "lbvs_intranet_http" 9 | ip_address: "10.10.11.21" 10 | port: 80 11 | service_type: "HTTP" 12 | lb_method: "LEASTCONNECTION" 13 | persistence: "SRCIPDESTIP" 14 | comment: "Intranet HTTP VIP" 15 | monitors: 16 | - name: "lbmon_intranet_http" 17 | type: "HTTP" 18 | request: "HEAD /healthcheck.html" 19 | secure: "YES" 20 | response_code: "200" 21 | bindings: 22 | vserver_to_servicegroup: 23 | - vserver_name: "lbvs_intranet_http" 24 | servicegroup_name: "svcgrp_intranet_http" 25 | servicegroup_to_servers: 26 | - servicegroup_name: "svcgrp_intranet_http" 27 | server_name: "prod_rhel_01" 28 | port: 80 29 | - servicegroup_name: "svcgrp_intranet_http" 30 | server_name: "prod_rhel_02" 31 | port: 80 32 | servicegroup_to_monitors: 33 | - servicegroup_name: "svcgrp_intranet_http" 34 | monitor_name: "lbmon_intranet_http" 35 | -------------------------------------------------------------------------------- /examples/netscaler_add_server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: PLAY 1 - ENSURE ALL SERVER OBJECTS EXIST 4 | hosts: netscaler 5 | connection: local 6 | gather_facts: False 7 | 8 | tasks: 9 | - name: TASK 1 - ENSURE SERVER OBJECTS ARE DEPLOYED 10 | netscaler_server: 11 | host: "{{ ansible_host }}" 12 | username: "{{ ansible_user }}" 13 | password: "{{ ansible_password }}" 14 | server_name: "{{ item.name }}" 15 | ip_address: "{{ item.ip_address }}" 16 | comment: "{{ item.comment | default('') }}" 17 | with_items: "{{ servers }}" 18 | 19 | - name: PLAY 2 - ENSURE ALL BINDINGS EXIST 20 | hosts: netscaler 21 | connection: local 22 | gather_facts: False 23 | 24 | tasks: 25 | - name: TASK 1 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS 26 | netscaler_servicegroup_server: 27 | host: "{{ ansible_host }}" 28 | username: "{{ ansible_user }}" 29 | password: "{{ ansible_password }}" 30 | servicegroup_name: "{{ item.servicegroup_name }}" 31 | server_name: "{{ item.server_name }}" 32 | server_port: "{{ item.port }}" 33 | with_items: "{{ bindings.servicegroup_to_servers }}" 34 | -------------------------------------------------------------------------------- /examples/vars/examples/full_partition.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | servers: 4 | - name: "prod_rhel_04" 5 | ip_address: "10.10.12.21" 6 | comment: "Dev Intranet Server" 7 | - name: "dr_rhel_04" 8 | ip_address: "10.10.22.21" 9 | comment: "Dev Backup Intranet Server" 10 | service_groups: 11 | - name: "svcgrp_dev_intranet_https" 12 | service_type: "SSL_BRIDGE" 13 | comment: "Dev Intranet Service Group" 14 | - name: "svcgrp_dev_backup_intranet_https" 15 | service_type: "SSL_BRIDGE" 16 | comment: "Dev Backup Intranet HTTPS Service Group" 17 | lb_vservers: 18 | - name: "lbvs_dev_intranet_https" 19 | ip_address: "10.10.13.21" 20 | port: 443 21 | backup_vserver: "lbvs_dev_backup_intranet_https" 22 | service_type: "SSL_BRIDGE" 23 | lb_method: "LEASTCONNECTION" 24 | persistence: "SRCIPDESTIP" 25 | comment: "Dev Intranet HTTPS VIP" 26 | lb_vservers_backup: 27 | - name: "lbvs_dev_backup_intranet_https" 28 | service_type: "SSL_BRIDGE" 29 | persistence: "SRCIPDESTIP" 30 | state: "disabled" 31 | comment: "Dev Backup Intranet HTTPS VIP" 32 | monitors: 33 | - name: "lbmon_dev_intranet_https" 34 | type: "HTTP" 35 | request: "HEAD /healthcheck.html" 36 | secure: "YES" 37 | response_code: "200-202" 38 | - name: "lbmon_dev_backup_intranet_https" 39 | type: "HTTP" 40 | request: "HEAD /healthcheck.html" 41 | secure: "YES" 42 | response_code: "200-202" 43 | bindings: 44 | vserver_to_servicegroup: 45 | - vserver_name: "lbvs_dev_intranet_https" 46 | servicegroup_name: "svcgrp_dev_intranet_https" 47 | - vserver_name: "lbvs_dev_backup_intranet_https" 48 | servicegroup_name: "svcgrp_dev_backup_intranet_https" 49 | servicegroup_to_servers: 50 | - servicegroup_name: "svcgrp_dev_intranet_https" 51 | server_name: "prod_rhel_04" 52 | port: 443 53 | - servicegroup_name: "svcgrp_dev_backup_intranet_https" 54 | server_name: "dr_rhel_04" 55 | port: 443 56 | servicegroup_to_monitors: 57 | - servicegroup_name: "svcgrp_dev_intranet_https" 58 | monitor_name: "lbmon_dev_intranet_https" 59 | - servicegroup_name: "svcgrp_dev_backup_intranet_https" 60 | monitor_name: "lbmon_dev_backup_intranet_https" 61 | partition: "UAT" -------------------------------------------------------------------------------- /examples/vars/examples/deploy_full.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | servers: 4 | - name: "prod_rhel_01" 5 | ip_address: "10.10.10.21" 6 | comment: "Intranet Server" 7 | - name: "prod_rhel_02" 8 | ip_address: "10.10.10.22" 9 | comment: "Intranet Server" 10 | - name: "dr_rhel_01" 11 | ip_address: "10.10.20.21" 12 | comment: "Backup Intranet Server" 13 | - name: "dr_rhel_02" 14 | ip_address: "10.10.20.22" 15 | comment: "Backup Intranet Server" 16 | service_groups: 17 | - name: "svcgrp_intranet_https" 18 | service_type: "SSL_BRIDGE" 19 | comment: "Intranet HTTPS Service Group" 20 | - name: "svcgrp_backup_intranet_https" 21 | service_type: "SSL_BRIDGE" 22 | comment: "Backup Intranet HTTPS Service Group" 23 | lb_vservers: 24 | - name: "lbvs_intranet_https" 25 | ip_address: "10.10.11.21" 26 | port: 443 27 | backup_vserver: "lbvs_backup_intranet_https" 28 | service_type: "SSL_BRIDGE" 29 | lb_method: "LEASTCONNECTION" 30 | persistence: "SRCIPDESTIP" 31 | conn_failover: "STATEFUL" 32 | comment: "Intranet HTTPS VIP" 33 | lb_vservers_backup: 34 | - name: "lbvs_backup_intranet_https" 35 | service_type: "SSL_BRIDGE" 36 | persistence: "SRCIPDESTIP" 37 | state: "disabled" 38 | comment: "Backup Intranet HTTPS VIP" 39 | monitors: 40 | - name: "lbmon_intranet_https" 41 | type: "HTTP" 42 | request: "HEAD /healthcheck.html" 43 | secure: "YES" 44 | response_code: "200-202" 45 | - name: "lbmon_backup_intranet_https" 46 | type: "HTTP" 47 | request: "HEAD /healthcheck.html" 48 | secure: "YES" 49 | response_code: "200-202" 50 | bindings: 51 | vserver_to_servicegroup: 52 | - vserver_name: "lbvs_intranet_https" 53 | servicegroup_name: "svcgrp_intranet_https" 54 | - vserver_name: "lbvs_backup_intranet_https" 55 | servicegroup_name: "svcgrp_backup_intranet_https" 56 | servicegroup_to_servers: 57 | - servicegroup_name: "svcgrp_intranet_https" 58 | server_name: "prod_rhel_01" 59 | port: 443 60 | - servicegroup_name: "svcgrp_intranet_https" 61 | server_name: "prod_rhel_02" 62 | port: 443 63 | - servicegroup_name: "svcgrp_backup_intranet_https" 64 | server_name: "dr_rhel_01" 65 | port: 443 66 | - servicegroup_name: "svcgrp_backup_intranet_https" 67 | server_name: "dr_rhel_02" 68 | port: 443 69 | servicegroup_to_monitors: 70 | - servicegroup_name: "svcgrp_intranet_https" 71 | monitor_name: "lbmon_intranet_https" 72 | - servicegroup_name: "svcgrp_backup_intranet_https" 73 | monitor_name: "lbmon_backup_intranet_https" 74 | -------------------------------------------------------------------------------- /examples/netscaler_deploy_vip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: PLAY 1 - ENSURE ALL LOAD BALANCER OBJECTS EXIST 4 | hosts: netscaler 5 | connection: local 6 | gather_facts: False 7 | 8 | tasks: 9 | - name: TASK 1 - ENSURE SERVICE GROUPS ARE DEPLOYED 10 | netscaler_servicegroup: 11 | host: "{{ ansible_host }}" 12 | username: "{{ ansible_user }}" 13 | password: "{{ ansible_password }}" 14 | servicegroup_name: "{{ item.name }}" 15 | service_type: "{{ item.service_type }}" 16 | comment: "{{ item.comment | default('') }}" 17 | with_items: "{{ service_groups }}" 18 | 19 | - name: TASK 2 - ENSURE LB VSERVERS ARE DEPLOYED 20 | netscaler_lbvserver: 21 | host: "{{ ansible_host }}" 22 | username: "{{ ansible_user }}" 23 | password: "{{ ansible_password }}" 24 | backup_lbvserver: "{{ item.backup_vserver | default('') }}" 25 | lbvserver_name: "{{ item.name }}" 26 | ip_address: "{{ item.ip_address }}" 27 | service_type: "{{ item.service_type | default('') }}" 28 | lbvserver_port: "{{ item.port | default('') }}" 29 | lbmethod: "{{ item.lb_method | default('LEASTCONNECTION') }}" 30 | persistence: "{{ item.persistence | default('') }}" 31 | conn_failover: "{{ item.conn_failover | default('DISABLED') }}" 32 | comment: "{{ item.comment | default('') }}" 33 | with_items: "{{ lb_vservers }}" 34 | 35 | - name: TASK 3 - ENSURE MONITORS ARE DEPLOYED 36 | netscaler_lbmonitor: 37 | host: "{{ ansible_host }}" 38 | username: "{{ ansible_user }}" 39 | password: "{{ ansible_password }}" 40 | monitor_name: "{{ item.name }}" 41 | monitor_type: "{{ item.type }}" 42 | http_request: "{{ item.request | default('') }}" 43 | monitor_use_ssl: "{{ item.secure | default('NO') }}" 44 | response_code: "{{ item.response_code | default([]) }}" 45 | when: monitors is defined 46 | with_items: "{{ monitors }}" 47 | 48 | 49 | 50 | - name: PLAY 2 - ENSURE ALL BINDINGS EXIST 51 | hosts: netscaler 52 | connection: local 53 | gather_facts: False 54 | 55 | tasks: 56 | - name: TASK 1 - ENSURE VSEVERS ARE BOUND TO SERVICEGROUPS 57 | netscaler_lbvserver_servicegroup: 58 | host: "{{ ansible_host }}" 59 | username: "{{ ansible_user }}" 60 | password: "{{ ansible_password }}" 61 | lbvserver_name: "{{ item.vserver_name }}" 62 | servicegroup_name: "{{ item.servicegroup_name }}" 63 | with_items: "{{ bindings.vserver_to_servicegroup }}" 64 | 65 | - name: TASK 2 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS 66 | netscaler_servicegroup_server: 67 | host: "{{ ansible_host }}" 68 | username: "{{ ansible_user }}" 69 | password: "{{ ansible_password }}" 70 | servicegroup_name: "{{ item.servicegroup_name }}" 71 | server_name: "{{ item.server_name }}" 72 | server_port: "{{ item.port }}" 73 | with_items: "{{ bindings.servicegroup_to_servers }}" 74 | 75 | - name: TASK 3 - ENSURE SERVICEGROUPS ARE BOUND TO MONITORS 76 | netscaler_servicegroup_monitor: 77 | host: "{{ ansible_host }}" 78 | username: "{{ ansible_user }}" 79 | password: "{{ ansible_password }}" 80 | servicegroup_name: "{{ item.servicegroup_name }}" 81 | monitor_name: "{{ item.monitor_name }}" 82 | with_items: "{{ bindings.servicegroup_to_monitors }}" 83 | -------------------------------------------------------------------------------- /unittests/netscaler_facts_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: GET ALL FACTS - NO CHANGE 9 | netscaler_facts: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | register: facts 14 | 15 | - name: ASSERT ALL KEYS ALL PRESENT 16 | assert: 17 | that: 18 | - "'ntc_system_data' in facts" 19 | - "'ntc_hardware_data' in facts" 20 | - "'ntc_interface_data' in facts" 21 | - "'ntc_lbvserver_stats' in facts" 22 | - "'ntc_config' in facts" 23 | - "'ntc_server_config' in facts" 24 | - "'ntc_service_group_config' in facts" 25 | - "'ntc_lbvserver_config' in facts" 26 | - "'ntc_monitor_config' in facts" 27 | 28 | - name: GET BASE FACTS - NO CHANGE 29 | netscaler_facts: 30 | host: "{{ inventory_hostname }}" 31 | username: "{{ username }}" 32 | password: "{{ password }}" 33 | gather_subset: "!all" 34 | register: facts 35 | 36 | - name: ASSERT ONLY THE SYSTEM_DATA KEY IS PRESENT 37 | assert: 38 | that: 39 | - "'ntc_system_data' in facts" 40 | - "'ntc_hardware_data' not in facts" 41 | - "'ntc_interface_data' not in facts" 42 | - "'ntc_lbvserver_stats' not in facts" 43 | - "'ntc_config' not in facts" 44 | - "'ntc_server_config' not in facts" 45 | - "'ntc_service_group_config' not in facts" 46 | - "'ntc_lbvserver_config' not in facts" 47 | - "'ntc_monitor_config' not in facts" 48 | 49 | - name: GET PARTIAL FACTS ASSERT FACTS - NO CHANGE 50 | netscaler_facts: 51 | host: "{{ inventory_hostname }}" 52 | username: "{{ username }}" 53 | password: "{{ password }}" 54 | gather_subset: 55 | - "lbvserver_config" 56 | - "monitor_config" 57 | - "hardware_data" 58 | register: facts 59 | 60 | - name: ASSERT ONLY THE SYSTEM_DATA, LBVSERVER_CONFIG, MONITOR_CONFIG, AND HARDWARE_DATA KEYS ARE PRESENT 61 | assert: 62 | that: 63 | - "'ntc_system_data' in facts" 64 | - "'ntc_hardware_data' in facts" 65 | - "'ntc_interface_data' not in facts" 66 | - "'ntc_lbvserver_stats' not in facts" 67 | - "'ntc_config' not in facts" 68 | - "'ntc_server_config' not in facts" 69 | - "'ntc_service_group_config' not in facts" 70 | - "'ntc_lbvserver_config' in facts" 71 | - "'ntc_monitor_config' in facts" 72 | 73 | - name: GET PARTIAL FACTS NEGATE FACTS - NO CHANGE 74 | netscaler_facts: 75 | host: "{{ inventory_hostname }}" 76 | username: "{{ username }}" 77 | password: "{{ password }}" 78 | gather_subset: 79 | - "!hardware_data" 80 | - "!config" 81 | - "!server_config" 82 | - "!lbvserver_stats" 83 | register: facts 84 | 85 | - name: ASSERT ALL KEYS ARE PRESENT EXCEPT FOR HARDWARE_DATA, CONFIG, SERVER_CONFIG, AND LBVSERVER_STATS 86 | assert: 87 | that: 88 | - "'ntc_system_data' in facts" 89 | - "'ntc_hardware_data' not in facts" 90 | - "'ntc_interface_data' in facts" 91 | - "'ntc_lbvserver_stats' not in facts" 92 | - "'ntc_config' not in facts" 93 | - "'ntc_server_config' not in facts" 94 | - "'ntc_service_group_config' in facts" 95 | - "'ntc_lbvserver_config' in facts" 96 | - "'ntc_monitor_config' in facts" 97 | 98 | - name: GET CONFIG FACTS FULL CONFIG - NO CHANGE 99 | netscaler_facts: 100 | host: "{{ inventory_hostname }}" 101 | username: "{{ username }}" 102 | password: "{{ password }}" 103 | gather_subset: 104 | - "config" 105 | config_scope: "true" 106 | 107 | - name: GET CONFIG FACTS NO HOST - FAIL 108 | netscaler_facts: 109 | username: "{{ username }}" 110 | password: "{{ password }}" 111 | gather_subset: 112 | - "config" 113 | config_scope: "true" 114 | ignore_errors: true 115 | -------------------------------------------------------------------------------- /examples.md: -------------------------------------------------------------------------------- 1 | # EXAMPLES 2 | 3 | ### Inventory File 4 | ``` 5 | [all:vars] 6 | ansible_python_interpreter=python 7 | ansible_user=username 8 | ansible_password=password 9 | 10 | [netscaler] 11 | netscaler1 ansible_host=10.1.1.1 12 | ``` 13 | 14 | ### Playbook 15 | ``` 16 | --- 17 | - name: CONFIGURE LOAD BALANCE VIP 18 | hosts: netscaler 19 | connection: local 20 | gather_facts: False 21 | 22 | tasks: 23 | - name: CONFIGURE SERVERS 24 | netscaler_server: 25 | host: "{{ ansible_host }}" 26 | username: "{{ ansible_user }}" 27 | password: "{{ ansible_password }}" 28 | server_name: "{{ item.name }}" 29 | ip_address: "{{ item.ip }}" 30 | comment: "{{ item.comment }}" 31 | with_items: 32 | - name: server01 33 | ip: 10.1.1.21 34 | comment: "First Server" 35 | - name: server02 36 | ip: 10.2.2.21 37 | comment: "Second Server" 38 | 39 | - name: CONFIGURE SERVICE GROUP 40 | netscaler_servicegroup: 41 | host: "{{ ansible_host }}" 42 | username: "{{ ansible_user }}" 43 | password: "{{ ansible_password }}" 44 | servicegroup_name: "sg_app01" 45 | service_type: "SSL" 46 | 47 | - name: CONFIGURE VSERVER 48 | netscaler_lbvserver: 49 | host: "{{ ansible_host }}" 50 | username: "{{ ansible_user }}" 51 | password: "{{ ansible_password }}" 52 | lbvserver_name: "vserver_app01" 53 | ip_address: "10.1.10.21" 54 | lbvserver_port: 443 55 | service_type: "SSL" 56 | lbmethod: "ROUNDROBIN" 57 | persistence: "SRCIPDESTIP" 58 | 59 | - name: CONFIGURE MONITOR 60 | netscaler_lbmonitor: 61 | host: "{{ ansible_host }}" 62 | username: "{{ ansible_user }}" 63 | password: "{{ ansible_password }}" 64 | monitor_name: "mon_app01" 65 | monitor_type: "HTTP" 66 | monitor_use_ssl: "YES" 67 | http_request: "HEAD /healthcheck.html" 68 | response_code: 69 | - "200-202" 70 | - "204" 71 | 72 | - name: BIND SERVICE GROUP TO SERVER 73 | netscaler_servicegroup_server: 74 | host: "{{ ansible_host }}" 75 | username: "{{ ansible_user }}" 76 | password: "{{ ansible_password }}" 77 | servicegroup_name: "sg_app01" 78 | server_name: "{{ item }}" 79 | server_port: 443 80 | with_items: 81 | - "server01" 82 | - "server02" 83 | 84 | - name: BIND SERVICE GROUP TO MONITOR 85 | netscaler_servicegroup_monitor: 86 | host: "{{ ansible_host }}" 87 | username: "{{ ansible_user }}" 88 | password: "{{ ansible_password }}" 89 | servicegroup_name: "sg_app01" 90 | monitor_name: "mon_app01" 91 | 92 | - name: BIND VSERVER TO SERVICE GROUP 93 | netscaler_lbvserver_servicegroup: 94 | host: "{{ ansible_host }}" 95 | username: "{{ ansible_user }}" 96 | password: "{{ ansible_password }}" 97 | lbvserver_name: "vserver_app01" 98 | servicegroup_name: "sg_app01" 99 | 100 | - name: BIND VSERVER TO CERT KEY 101 | netscaler_vserver_certkey: 102 | host: "{{ ansible_host }}" 103 | username: "{{ ansible_user }}" 104 | password: "{{ ansible_password }}" 105 | vserver_name: "vserver_app01" 106 | cert_key_name: "ck_app01" 107 | 108 | - name: SAVE CONFIG 109 | netscaler_save_config: 110 | host: "{{ ansible_host }}" 111 | username: "{{ ansible_user }}" 112 | password: "{{ ansible_password }}" 113 | ``` 114 | 115 | ## Netscaler Facts 116 | ``` 117 | --- 118 | - name: SHOW DIFFERENT WAYS TO USE THE FACTS MODULE 119 | hosts: all 120 | connection: local 121 | gather_facts: False 122 | 123 | tasks: 124 | - name: GET ALL FACTS 125 | netscaler_facts: 126 | host: "{{ ansible_host }}" 127 | username: "{{ ansible_user }}" 128 | password: "{{ ansible_password }}" 129 | 130 | - name: GET SOME FACTS USING INCLUDE METHOD 131 | netscaler_facts: 132 | host: "{{ ansible_host }}" 133 | username: "{{ ansible_user }}" 134 | password: "{{ ansible_password }}" 135 | gather_subset: 136 | - "hardware_data" 137 | - "interface_data" 138 | - "lbvserver_stats" 139 | 140 | - name: GET SOME FACTS USING EXCLUDE METHOD 141 | netscaler_facts: 142 | host: "{{ ansible_host }}" 143 | username: "{{ ansible_user }}" 144 | password: "{{ ansible_password }}" 145 | gather_subset: 146 | - "!config" 147 | - "!server_config" 148 | 149 | - name: GET ONLY SYSTEM FACTS 150 | netscaler_facts: 151 | host: "{{ ansible_host }}" 152 | username: "{{ ansible_user }}" 153 | password: "{{ ansible_password }}" 154 | gather_subset: 155 | - "!all" 156 | ``` -------------------------------------------------------------------------------- /examples/netscaler_deploy_full.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: PLAY 1 - ENSURE ALL LOAD BALANCER OBJECTS EXIST 4 | hosts: netscaler 5 | connection: local 6 | gather_facts: False 7 | 8 | tasks: 9 | - name: TASK 1 - ENSURE SERVER OBJECTS ARE DEPLOYED 10 | netscaler_server: 11 | host: "{{ ansible_host }}" 12 | username: "{{ ansible_user }}" 13 | password: "{{ ansible_password }}" 14 | server_name: "{{ item.name }}" 15 | ip_address: "{{ item.ip_address }}" 16 | comment: "{{ item.comment | default('') }}" 17 | partition: "{{ partition | default('') }}" 18 | with_items: "{{ servers }}" 19 | 20 | - name: TASK 2 - ENSURE SERVICE GROUPS ARE DEPLOYED 21 | netscaler_servicegroup: 22 | host: "{{ ansible_host }}" 23 | username: "{{ ansible_user }}" 24 | password: "{{ ansible_password }}" 25 | servicegroup_name: "{{ item.name }}" 26 | service_type: "{{ item.service_type }}" 27 | comment: "{{ item.comment | default('') }}" 28 | partition: "{{ partition | default('') }}" 29 | with_items: "{{ service_groups }}" 30 | 31 | - name: TASK 3 - ENSURE BACKUP LB VSERVERS ARE DEPLOYED 32 | netscaler_lbvserver: 33 | host: "{{ ansible_host }}" 34 | username: "{{ ansible_user }}" 35 | password: "{{ ansible_password }}" 36 | lbvserver_name: "{{ item.name }}" 37 | service_type: "{{ item.service_type | default('') }}" 38 | lbmethod: "{{ item.lbmethod | default('LEASTCONNECTION') }}" 39 | persistence: "{{ item.persistence | default('') }}" 40 | lbvserver_state: "disabled" 41 | comment: "{{ item.comment | default() }}" 42 | partition: "{{ partition | default('') }}" 43 | when: lb_vservers_backup is defined 44 | with_items: "{{ lb_vservers_backup }}" 45 | 46 | - name: TASK 4 - ENSURE LB VSERVERS ARE DEPLOYED 47 | netscaler_lbvserver: 48 | host: "{{ ansible_host }}" 49 | username: "{{ ansible_user }}" 50 | password: "{{ ansible_password }}" 51 | backup_lbvserver: "{{ item.backup_vserver | default('') }}" 52 | lbvserver_name: "{{ item.name }}" 53 | ip_address: "{{ item.ip_address }}" 54 | service_type: "{{ item.service_type | default('') }}" 55 | lbvserver_port: "{{ item.port | default('') }}" 56 | lbmethod: "{{ item.lb_method | default('LEASTCONNECTION') }}" 57 | persistence: "{{ item.persistence | default('') }}" 58 | conn_failover: "{{ item.conn_failover | default('DISABLED') }}" 59 | comment: "{{ item.comment | default('') }}" 60 | partition: "{{ partition | default('') }}" 61 | with_items: "{{ lb_vservers }}" 62 | 63 | - name: TASK 5 - ENSURE MONITORS ARE DEPLOYED 64 | netscaler_lbmonitor: 65 | host: "{{ ansible_host }}" 66 | username: "{{ ansible_user }}" 67 | password: "{{ ansible_password }}" 68 | monitor_name: "{{ item.name }}" 69 | monitor_type: "{{ item.type }}" 70 | http_request: "{{ item.request | default('') }}" 71 | monitor_use_ssl: "{{ item.secure | default('NO') }}" 72 | response_code: "{{ item.response_code | default([]) }}" 73 | partition: "{{ partition | default('') }}" 74 | when: monitors is defined 75 | with_items: "{{ monitors }}" 76 | 77 | 78 | 79 | - name: PLAY 2 - ENSURE ALL BINDINGS EXIST 80 | hosts: netscaler 81 | connection: local 82 | gather_facts: False 83 | 84 | tasks: 85 | - name: TASK 1 - ENSURE VSEVERS ARE BOUND TO SERVICEGROUPS 86 | netscaler_lbvserver_servicegroup: 87 | host: "{{ ansible_host }}" 88 | username: "{{ ansible_user }}" 89 | password: "{{ ansible_password }}" 90 | lbvserver_name: "{{ item.vserver_name }}" 91 | servicegroup_name: "{{ item.servicegroup_name }}" 92 | partition: "{{ partition | default('') }}" 93 | with_items: "{{ bindings.vserver_to_servicegroup }}" 94 | 95 | - name: TASK 2 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS 96 | netscaler_servicegroup_server: 97 | host: "{{ ansible_host }}" 98 | username: "{{ ansible_user }}" 99 | password: "{{ ansible_password }}" 100 | servicegroup_name: "{{ item.servicegroup_name }}" 101 | server_name: "{{ item.server_name }}" 102 | server_port: "{{ item.port }}" 103 | partition: "{{ partition | default('') }}" 104 | with_items: "{{ bindings.servicegroup_to_servers }}" 105 | 106 | - name: TASK 3 - ENSURE SERVICEGROUPS ARE BOUND TO MONITORS 107 | netscaler_servicegroup_monitor: 108 | host: "{{ ansible_host }}" 109 | username: "{{ ansible_user }}" 110 | password: "{{ ansible_password }}" 111 | servicegroup_name: "{{ item.servicegroup_name }}" 112 | monitor_name: "{{ item.monitor_name }}" 113 | partition: "{{ partition | default('') }}" 114 | with_items: "{{ bindings.servicegroup_to_monitors }}" 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Ansible Modules for Netscaler Nitro API 3 | 4 | * [Introduction](#introduction) 5 | * [Module Summary](#modules) 6 | * [Installation](#installation) 7 | * [Detailed Module Documentation](#full-module-documentation) 8 | * [Module Examples](#examples) 9 | * [Contributing](#contributing) 10 | 11 | # Introduction 12 | 13 | This repository includes a number of Ansible modules to automate Citrix Netscaler devices using the Nitro API. 14 | 15 | # Modules 16 | 17 | Here is a brief overview of all modules included in this repository. 18 | 19 | * **netscaler_server** 20 | + Used to create, update, and delete server objects. 21 | + Returns the existing configuration for the server object and the configuration sent to the Netscaler API. 22 | * **netscaler_servicegroup** 23 | + Used to create, update, and delete service group objects. 24 | + Returns the existing configuration for the service group and the configuration sent to the Netscaler API. 25 | * **netscaler_lbvserver** 26 | + Used to create, update, and delete lb vserver objects. 27 | + Returns the existing configuration for the lb vserver and the configuration sent to the Netscaler API. 28 | * **netscaler_lbmonitor** 29 | + Used to create, update, and delete lb monitor objects. 30 | + Returns the existing configuration for the lb monitor and the configuration sent to the Netscaler API. 31 | * **netscaler_servicegroup_server** 32 | + Used to create and delete service group to server bindings. 33 | + Returns all existing server objects bound to the service group, the existing configuration for the particular service group to server pair, and the configuration sent to the Netscaler API. 34 | * **netscaler_servicegroup_monitor** 35 | + Used to create and delete service group to lb monitor bindings. 36 | + Returns all existing lb monitors bound to the service group, the existing configuration for the particular service group to lb monitor pair, and the configuration sent to the Netscaler API. 37 | * **netscaler_lbvserver_servicegroup** 38 | + Used to create and delete lb vserver to service group bindings. 39 | + Returns all existing service groups bound to the lb vserver, the existing configuration for the particular lb vserver to service group pair, and the configuration sent to the Netscaler API. 40 | * **netscaler_lbvserver_certkey** 41 | + Used to create, update, and delete lb vserver to SSl cert key bindings. 42 | + Returns all existing SSl cert keys bound to the lb vserver, the existing configuration for the particular lb vserver to SSL cert key pair, and the configuration sent to the Netscaler API. 43 | * **netscaler_facts** 44 | + Used to gather facts about the Netscaler system and configuration. 45 | + Returns system and hardware info, cli configuration, and json configurations for servers, service groups, lb vservers, and lb monitors. 46 | * **netscaler_save_config** 47 | + Used to save the running configuration on the Netscaler to the device. 48 | + Returns the status code of the API request to save the configuration. 49 | 50 | # Installation 51 | 52 | You need to perform **two** steps to start using these modules. 53 | 54 | 1. Ensure this repository is in your Ansible module search path. 55 | 2. Install Dependencies. 56 | 57 | ### Locate your search path 58 | Here is how you can locate your search path: 59 | ``` 60 | $ ansible --version 61 | ansible 2.1.1.0 62 | config file = /etc/ansible/ansible.cfg 63 | configured module search path = ??? 64 | ``` 65 | 66 | If you already have a search path configured, clone the repo (see options below) while you are in your search path. 67 | 68 | If you have a "default" or No search path shown, open the config file that is shown in the output above, here that is `/etc/ansible/ansible.cfg`. In that file, you'll see these first few lines: 69 | ``` 70 | [defaults] 71 | 72 | # some basic default values... 73 | 74 | inventory = /etc/ansible/hosts 75 | library = /home/ntc/projects/ 76 | ``` 77 | 78 | Add a path for `library` that exists in this repository - this will become your search path. Validate it with `ansible --version` after you make the change. 79 | 80 | ### Clone the repo in your search path 81 | Once you have located your search path; browse to that directory and clone the netscaler-ansible repo: 82 | ``` 83 | $ cd /home/ntc/projects 84 | $ git clone https://github.com/networktocode/netscaler-ansible.git 85 | ``` 86 | 87 | As a quick test and sanity-check use `ansible-doc` on one of the modules before trying to use them in a playbook. For example, try this: 88 | ``` 89 | $ ansible-doc netscaler_save_config 90 | ``` 91 | 92 | If that works, Ansible can find the modules and you can proceed to installing the dependencies below. 93 | 94 | ## Install Dependencies 95 | All of the dependencies can be installed using the requirements.txt file that comes with the modules. Move to the new netscaler-ansible directory and use pip to install them. 96 | ``` 97 | $ cd netscaler-ansible 98 | $ pip install -r requirements.txt 99 | ``` 100 | 101 | 102 | # Full Module Documentation 103 | 104 | The following docs are the same type of docs you'd find on docs.ansible.com for modules that are found in Ansible core: 105 | 106 | See [Module Documentation](Module_Docs/netscaler_module_docs.md) 107 | 108 | # Examples 109 | See [Examples](examples.md) 110 | 111 | # Contributing 112 | See [Contributing](contributing.md) -------------------------------------------------------------------------------- /unittests/netscaler_lbvserver_certkey_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PREPARE OBJECTS 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CREATE LB VSERVERS - CHANGE 9 | netscaler_lbvserver: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | lbvserver_name: "{{ item.name }}" 14 | ip_address: "{{ item.ip }}" 15 | lbvserver_port: 80 16 | service_type: "SSL" 17 | partition: "{{ item.partition | default('default') }}" 18 | with_items: 19 | - name: "vserver01" 20 | ip: "10.1.1.21" 21 | - name: "vserver02" 22 | ip: "10.1.1.22" 23 | - name: "vserver01" 24 | ip: "10.1.1.21" 25 | partition: "LAB" 26 | 27 | 28 | - name: UNITTEST 29 | hosts: netscaler 30 | connection: local 31 | gather_facts: False 32 | 33 | tasks: 34 | - name: CREATE VSERVER BINDING TO CERT KEY BINDING - CHANGE 35 | netscaler_lbvserver_certkey: 36 | host: "{{ inventory_hostname }}" 37 | username: "{{ username }}" 38 | password: "{{ password }}" 39 | vserver_name: "vserver01" 40 | cert_key_name: "test" 41 | 42 | - name: CREATE VSERVER BINDING TO CERT KEY BINDING AGAIN - NO CHANGE 43 | netscaler_lbvserver_certkey: 44 | host: "{{ inventory_hostname }}" 45 | username: "{{ username }}" 46 | password: "{{ password }}" 47 | vserver_name: "vserver01" 48 | cert_key_name: "test" 49 | 50 | - name: CREATE VSERVER BINDING TO CERT KEY BINDING IN PARTITION - CHANGE 51 | netscaler_lbvserver_certkey: 52 | host: "{{ inventory_hostname }}" 53 | username: "{{ username }}" 54 | password: "{{ password }}" 55 | vserver_name: "vserver01" 56 | cert_key_name: "test" 57 | partition: "LAB" 58 | 59 | - name: REMOVE VSERVER TO CERT KEY BINDING - CHANGE 60 | netscaler_lbvserver_certkey: 61 | host: "{{ inventory_hostname }}" 62 | username: "{{ username }}" 63 | password: "{{ password }}" 64 | vserver_name: "vserver01" 65 | cert_key_name: "test" 66 | partition: "LAB" 67 | state: "absent" 68 | 69 | - name: REMOVE VSERVER TO CERT KEY BINDING AGAIN - NO CHANGE 70 | netscaler_lbvserver_certkey: 71 | host: "{{ inventory_hostname }}" 72 | username: "{{ username }}" 73 | password: "{{ password }}" 74 | vserver_name: "vserver01" 75 | cert_key_name: "test" 76 | partition: "LAB" 77 | state: "absent" 78 | 79 | - name: CREATE VSERVER TO CERT KEY BINDING NO HOST - FAIL 80 | netscaler_lbvserver_certkey: 81 | username: "{{ username }}" 82 | password: "{{ password }}" 83 | vserver_name: "vserver01" 84 | cert_key_name: "test" 85 | ignore_errors: yes 86 | 87 | - name: CREATE VSERVER TO CERT KEY BINDING NO VSERVER NAME - FAIL 88 | netscaler_lbvserver_certkey: 89 | host: "{{ inventory_hostname }}" 90 | username: "{{ username }}" 91 | password: "{{ password }}" 92 | cert_key_name: "test" 93 | ignore_errors: yes 94 | 95 | - name: CREATE VSERVER TO CERT KEY BINDING NO CERT KEY NAME - FAIL 96 | netscaler_lbvserver_certkey: 97 | host: "{{ inventory_hostname }}" 98 | username: "{{ username }}" 99 | password: "{{ password }}" 100 | vserver_name: "vserver01" 101 | ignore_errors: yes 102 | 103 | - name: CREATE VSERVER TO CERT KEY BINDING VSERVER DOES NOT EXIST - FAIL 104 | netscaler_lbvserver_certkey: 105 | host: "{{ inventory_hostname }}" 106 | username: "{{ username }}" 107 | password: "{{ password }}" 108 | vserver_name: "vserver" 109 | cert_key_name: "test" 110 | ignore_errors: yes 111 | 112 | - name: CREATE VSERVER TO CERT KEY BINDING CERT KEY DOES NOT EXIST - FAIL 113 | netscaler_lbvserver_certkey: 114 | host: "{{ inventory_hostname }}" 115 | username: "{{ username }}" 116 | password: "{{ password }}" 117 | vserver_name: "vserver01" 118 | cert_key_name: "cert" 119 | ignore_errors: yes 120 | 121 | 122 | 123 | - name: UNITTEST CLEANUP 124 | hosts: netscaler 125 | connection: local 126 | gather_facts: False 127 | 128 | tasks: 129 | - name: CLEANUP BINDINGS - CHANGE 130 | netscaler_lbvserver_certkey: 131 | host: "{{ inventory_hostname }}" 132 | username: "{{ username }}" 133 | password: "{{ password }}" 134 | state: "absent" 135 | vserver_name: "{{ item.vserver }}" 136 | cert_key_name: "{{ item.servicegroup }}" 137 | partition: "{{ item.partition | default('default') }}" 138 | with_items: 139 | - vserver: "vserver01" 140 | servicegroup: "test" 141 | - vserver: "vserver01" 142 | servicegroup: "test" 143 | - vserver: "vserver01" 144 | servicegroup: "test" 145 | partition: "LAB" 146 | 147 | 148 | 149 | - name: PREPARE OBJECTS CLEANUP 150 | hosts: netscaler 151 | connection: local 152 | gather_facts: False 153 | tags: cleanup 154 | 155 | tasks: 156 | - name: CLEANUP VSERVERS - CHANGE 157 | netscaler_lbvserver: 158 | host: "{{ inventory_hostname }}" 159 | username: "{{ username }}" 160 | password: "{{ password }}" 161 | lbvserver_name: "{{ item.name }}" 162 | partition: "{{ item.partition | default('default') }}" 163 | state: "absent" 164 | with_items: 165 | - name: "vserver01" 166 | - name: "vserver02" 167 | - name: "vserver01" 168 | partition: "LAB" -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing Details 2 | 3 | ## Notes 4 | Each module currently has the base `Netscaler` class and any additional sub-classes that are needed for the module execution. The goal is to have all of the classes function as a module_utils file, but are currently appended to each module for ease of consumption. This also means that each base documentation option must be included in each module instead of using `extends_documentation_fragment`. 5 | 6 | Enhancements and bug fixes are welcome, just submit a pull request and provide some information on why it is needed and what it is aimed to enhance or fix. 7 | 8 | ## Classes Vs. Methods 9 | The design method for creating a new class versus creating methods inside of an existing class are: 10 | 11 | 1. Creating, Updating, and Deleting objects get their own class. 12 | 2. Binding objects together should be done with methods inside the class that corresponds to first class listed in the API Endpoint. 13 | 14 | ##### EXAMPLE: 15 | Creating, updating, and deleting lbvserver objects would be its own defined class, LBVServer. 16 | 17 | Binding an lbvserver object to a servicegroup object would be a set of methods in the LBVServer class since the goal is to bind obects together and the API endpoint is "**lbvserver**_servicegroup_binding" 18 | 19 | ## Class Methodology 20 | Each new class should inherit the base `Netscaler` class, which is where all common methods are defined. The new sub-class should define the `api_endpoint` for the object when defining `__init__`. Sub-classes should only have methods defined when: 21 | 22 | 1. There is a need to override the base class' implementation. 23 | * Example would be methods that define a `name` key, but the particular API endpoint does not follow the "standard" Nitro naming convention (ServiceGroup is an example). 24 | 2. The class needs a method that is unique to it. 25 | * Example would be a binding method. 26 | 27 | ## Method Methodology 28 | Most methods defined are used to either make an API request to the Netscaler, or to modify the data returned from an API request. There are a few Ansible specific methods that are used to handle the logic of the corresponding Ansible Module (thus making the creation of new modules easier and consistent with existing modules): 29 | 30 | 1. `config_new` is used to handle the logic of configuring a new object on the Netscaler. This supports checkmode, fails the module if an API request fails, and returns the config key that is returned by the Ansible Module. 31 | 32 | 2. `config_update` is used to handle the logic of updating and existing object's configuration on the Netscaler. This supports checkmode, fails the module if an API request fails, and returns the config key that is returned by the Ansible Module. 33 | 34 | 3. `config_delete` is used to handle the logic of deleting an existing object on the Netscaler. This supports checkmode, fails the module if an API request fails, and returns the config key that is returned by the Ansible Module. 35 | 36 | Since these are the only 3 modules that are Ansible specefic, and these modules use methods in the class to perform API requests, it is easy to use and debug in a Python shell. 37 | 38 | Methods used to handle logic should not make API requests, but should call a method whose sole purpose is to return either the response or response content from an API request. 39 | 40 | Methods that make API requests should not be handling logic required to obtain some other goal. 41 | 42 | ## Module Methodology 43 | The base `Argument Specs` that should be supported are: 44 | ``` 45 | host=dict(required=True, type="str"), 46 | port=dict(required=False, type="int"), 47 | username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])), 48 | password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), o_log=True), 49 | use_ssl=dict(default=True, type="bool"), 50 | validate_certs=dict(default=False, type="bool"), 51 | provider=dict(required=False, type="dict"), 52 | state=dict(choices=["absent", "present"], default="present", type="str"), 53 | partition=dict(required=False, type="str") 54 | ``` 55 | >Provider should not log password values, and should be overridden by duplicate values specified as a local param. 56 | 57 | The module specific args are put into a dictionary, with the unused (null value) arguments being omitted. This method is done to prevent existing objects from being accidently changed to Netscaler's default value. 58 | 59 | After login, the very next step should be to switch to the partition if defined in the module args. This is important since the Netscaler does not support passing a "partition" argument with an API request. The `Netscaler`'s `login` and `switch_partition` methods handle this for you. 60 | 61 | The next step is to retrieve the object or binding configuration from the Netscaler (this should be based on the object's name). 62 | 63 | The next step is to determine if the `state` is set to "present" or "absent" and pass the necessary args to either a `change_config` or `delete_config` function. These functions should handle the rest of the necessary Ansible logic and return back the results dictionary that the Ansible Module will return back to the terminal. 64 | 65 | The `change_config` function will need to determine if the configuration needs to create a new object or binding, or update the existing configuration. The `get_diff` method returns a tuble of two values: 66 | 67 | 1. config_method can be either: 68 | * "new" - meaning the object or binding currently does not exist. 69 | * "update" - meaning the object or binding does exist, but there are differences between what was submitted in the task and the current configuration. 70 | * "none" - meaning the proposed and existing configuration are identical. 71 | 2. config_diff can be either: 72 | * The configuration difference between proposed and existing configuration (only values that are different than existing are in the dict). 73 | * An empty dict if proposed and existing are identical. 74 | 75 | Once you have the config_method and config_diff, you can perfrom any desired tests and use the config_new or config_update methods to make the necessary changes. 76 | 77 | The `delete_config` function should check that the object or binding exists on the Netscaler, and then call the `config_delete` method if there is configuration to be removed. 78 | 79 | -------------------------------------------------------------------------------- /unittests/netscaler_lbvserver_servicegroup_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PREPARE OBJECTS 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CREATE LB VSERVERS - CHANGE 9 | netscaler_lbvserver: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | lbvserver_name: "{{ item.name }}" 14 | ip_address: "{{ item.ip }}" 15 | lbvserver_port: 80 16 | service_type: "HTTP" 17 | partition: "{{ item.partition | default('default') }}" 18 | with_items: 19 | - name: "vserver01" 20 | ip: "10.1.1.21" 21 | - name: "vserver02" 22 | ip: "10.1.1.22" 23 | - name: "vserver01" 24 | ip: "10.1.1.21" 25 | partition: "LAB" 26 | 27 | - name: CREATE SERVICE GROUPS - CHANGE 28 | netscaler_servicegroup: 29 | host: "{{ inventory_hostname }}" 30 | username: "{{ username }}" 31 | password: "{{ password }}" 32 | servicegroup_name: "{{ item.servicegroup }}" 33 | service_type: "HTTP" 34 | partition: "{{ item.partition | default('default')}}" 35 | with_items: 36 | - servicegroup: "servicegroup01" 37 | - servicegroup: "servicegroup02" 38 | - servicegroup: "servicegroup01" 39 | partition: "LAB" 40 | 41 | 42 | - name: UNITTEST 43 | hosts: netscaler 44 | connection: local 45 | gather_facts: False 46 | 47 | tasks: 48 | - name: CREATE SERVICE GROUP TO VSERVER BINDING - CHANGE 49 | netscaler_lbvserver_servicegroup: 50 | host: "{{ inventory_hostname }}" 51 | username: "{{ username }}" 52 | password: "{{ password }}" 53 | lbvserver_name: "vserver01" 54 | servicegroup_name: "servicegroup01" 55 | 56 | - name: CREATE SERVICE GROUP TO VSERVER BINDING AGAIN - NO CHANGE 57 | netscaler_lbvserver_servicegroup: 58 | host: "{{ inventory_hostname }}" 59 | username: "{{ username }}" 60 | password: "{{ password }}" 61 | lbvserver_name: "vserver01" 62 | servicegroup_name: "servicegroup01" 63 | 64 | - name: CREATE SERVICE GROUP TO VSERVER BINDING IN PARTITION - CHANGE 65 | netscaler_lbvserver_servicegroup: 66 | host: "{{ inventory_hostname }}" 67 | username: "{{ username }}" 68 | password: "{{ password }}" 69 | lbvserver_name: "vserver01" 70 | servicegroup_name: "servicegroup01" 71 | partition: "LAB" 72 | 73 | - name: REMOVE SERVICE GROUP TO VSERVER BINDING - CHANGE 74 | netscaler_lbvserver_servicegroup: 75 | host: "{{ inventory_hostname }}" 76 | username: "{{ username }}" 77 | password: "{{ password }}" 78 | lbvserver_name: "vserver01" 79 | servicegroup_name: "servicegroup01" 80 | partition: "LAB" 81 | state: "absent" 82 | 83 | - name: REMOVE SERVICE GROUP TO VSERVER BINDING AGAIN - NO CHANGE 84 | netscaler_lbvserver_servicegroup: 85 | host: "{{ inventory_hostname }}" 86 | username: "{{ username }}" 87 | password: "{{ password }}" 88 | lbvserver_name: "vserver01" 89 | servicegroup_name: "servicegroup01" 90 | partition: "LAB" 91 | state: "absent" 92 | 93 | - name: CREATE SERVICE GROUP TO VSERVER BINDING AGAIN - NO CHANGE 94 | set_fact: 95 | provider: 96 | host: "{{ inventory_hostname }}" 97 | username: "{{ username }}" 98 | password: "{{ password }}" 99 | lbvserver_name: "vserver01" 100 | servicegroup_name: "servicegroup01" 101 | 102 | - name: CREATE SERVICE GROUP TO VSERVER BINDING WITH PROVIDER - NO CHANGE 103 | netscaler_lbvserver_servicegroup: 104 | provider: "{{ provider }}" 105 | 106 | - name: CREATE SERVICE GROUP TO VSERVER BINDING OVERRIDE PROVIDER - CHANGE 107 | netscaler_lbvserver_servicegroup: 108 | provider: "{{ provider }}" 109 | lbvserver_name: "vserver02" 110 | servicegroup_name: "servicegroup02" 111 | 112 | - name: CREATE SERVICE GROUP TO VSERVER BINDING NO HOST - FAIL 113 | netscaler_lbvserver_servicegroup: 114 | username: "{{ username }}" 115 | password: "{{ password }}" 116 | lbvserver_name: "vserver01" 117 | servicegroup_name: "servicegroup01" 118 | ignore_errors: yes 119 | 120 | - name: CREATE SERVICE GROUP TO VSERVER BINDING NO VSERVER NAME - FAIL 121 | netscaler_lbvserver_servicegroup: 122 | host: "{{ inventory_hostname }}" 123 | username: "{{ username }}" 124 | password: "{{ password }}" 125 | servicegroup_name: "servicegroup01" 126 | ignore_errors: yes 127 | 128 | - name: CREATE SERVICE GROUP TO VSERVER BINDING NO SERVICE GROUP NAME - FAIL 129 | netscaler_lbvserver_servicegroup: 130 | host: "{{ inventory_hostname }}" 131 | username: "{{ username }}" 132 | password: "{{ password }}" 133 | lbvserver_name: "vserver01" 134 | ignore_errors: yes 135 | 136 | - name: CREATE SERVICE GROUP TO VSERVER BINDING VSERVER DOES NOT EXIST - FAIL 137 | netscaler_lbvserver_servicegroup: 138 | host: "{{ inventory_hostname }}" 139 | username: "{{ username }}" 140 | password: "{{ password }}" 141 | lbvserver_name: "vserver" 142 | servicegroup_name: "servicegroup01" 143 | ignore_errors: yes 144 | 145 | - name: CREATE SERVICE GROUP TO VSERVER BINDING SERVICE GROUP DOES NOT EXIST - FAIL 146 | netscaler_lbvserver_servicegroup: 147 | host: "{{ inventory_hostname }}" 148 | username: "{{ username }}" 149 | password: "{{ password }}" 150 | lbvserver_name: "vserver01" 151 | servicegroup_name: "servicegroup" 152 | ignore_errors: yes 153 | 154 | 155 | 156 | - name: UNITTEST CLEANUP 157 | hosts: netscaler 158 | connection: local 159 | gather_facts: False 160 | 161 | tasks: 162 | - name: CLEANUP BINDINGS - CHANGE 163 | netscaler_lbvserver_servicegroup: 164 | host: "{{ inventory_hostname }}" 165 | username: "{{ username }}" 166 | password: "{{ password }}" 167 | state: "absent" 168 | lbvserver_name: "{{ item.vserver }}" 169 | servicegroup_name: "{{ item.servicegroup }}" 170 | partition: "{{ item.partition | default('default') }}" 171 | with_items: 172 | - vserver: "vserver01" 173 | servicegroup: "servicegroup01" 174 | - vserver: "vserver02" 175 | servicegroup: "servicegroup02" 176 | - vserver: "vserver01" 177 | servicegroup: "servicegroup01" 178 | partition: "LAB" 179 | 180 | 181 | 182 | - name: PREPARE OBJECTS CLEANUP 183 | hosts: netscaler 184 | connection: local 185 | gather_facts: False 186 | 187 | tasks: 188 | - name: CLEANUP SERVERS - CHANGE 189 | netscaler_lbvserver: 190 | host: "{{ inventory_hostname }}" 191 | username: "{{ username }}" 192 | password: "{{ password }}" 193 | lbvserver_name: "{{ item.name }}" 194 | partition: "{{ item.partition | default('default') }}" 195 | state: "absent" 196 | with_items: 197 | - name: "vserver01" 198 | - name: "vserver02" 199 | - name: "vserver01" 200 | partition: "LAB" 201 | 202 | - name: CLEANUP SERVICE GROUPS - CHANGE 203 | netscaler_servicegroup: 204 | host: "{{ inventory_hostname }}" 205 | username: "{{ username }}" 206 | password: "{{ password }}" 207 | servicegroup_name: "{{ item.servicegroup }}" 208 | partition: "{{ item.partition | default('default')}}" 209 | state: "absent" 210 | with_items: 211 | - servicegroup: "servicegroup01" 212 | - servicegroup: "servicegroup02" 213 | - servicegroup: "servicegroup01" 214 | partition: "LAB" -------------------------------------------------------------------------------- /unittests/netscaler_server_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CONFIG SERVER - CHANGE 9 | netscaler_server: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | server_name: "server01" 14 | ip_address: "10.1.1.21" 15 | 16 | - name: CONFIG SERVER AGAIN - NO CHANGE 17 | netscaler_server: 18 | host: "{{ inventory_hostname }}" 19 | username: "{{ username }}" 20 | password: "{{ password }}" 21 | server_name: "server01" 22 | ip_address: "10.1.1.21" 23 | 24 | - name: ADD COMMENT TO SERVER - CHANGE 25 | netscaler_server: 26 | host: "{{ inventory_hostname }}" 27 | username: "{{ username }}" 28 | password: "{{ password }}" 29 | server_name: "server01" 30 | ip_address: "10.1.1.21" 31 | comment: "Comments Work" 32 | 33 | - name: CONFIG SERVER IN LAB PARTITION - CHANGE 34 | netscaler_server: 35 | host: "{{ inventory_hostname }}" 36 | username: "{{ username }}" 37 | password: "{{ password }}" 38 | server_name: "server02" 39 | ip_address: "10.1.1.22" 40 | partition: "LAB" 41 | 42 | - name: CONFIG SERVER IN DISABLED STATE - CHANGE 43 | netscaler_server: 44 | host: "{{ inventory_hostname }}" 45 | username: "{{ username }}" 46 | password: "{{ password }}" 47 | server_name: "server03" 48 | ip_address: "10.1.1.23" 49 | server_state: "disabled" 50 | 51 | - name: ENABLE SERVER IN DISABLED STATE - CHANGE 52 | netscaler_server: 53 | host: "{{ inventory_hostname }}" 54 | username: "{{ username }}" 55 | password: "{{ password }}" 56 | server_name: "server03" 57 | server_state: "enabled" 58 | 59 | - name: DISABLE SERVER IN ENABLED STATE - CHANGE 60 | netscaler_server: 61 | host: "{{ inventory_hostname }}" 62 | username: "{{ username }}" 63 | password: "{{ password }}" 64 | server_name: "server01" 65 | ip_address: "10.1.1.21" 66 | server_state: "disabled" 67 | 68 | - name: CONFIG SERVER WITH A COMMENT - CHANGE 69 | netscaler_server: 70 | host: "{{ inventory_hostname }}" 71 | username: "{{ username }}" 72 | password: "{{ password }}" 73 | server_name: "server04" 74 | ip_address: "10.1.1.24" 75 | comment: "Comments Still Work" 76 | 77 | - name: MODIFY A SERVER'S COMMENT - CHANGE 78 | netscaler_server: 79 | host: "{{ inventory_hostname }}" 80 | username: "{{ username }}" 81 | password: "{{ password }}" 82 | server_name: "server04" 83 | comment: "Comments are Changeable." 84 | 85 | - name: DELETE SERVER - CHANGE 86 | netscaler_server: 87 | host: "{{ inventory_hostname }}" 88 | username: "{{ username }}" 89 | password: "{{ password }}" 90 | server_name: "server01" 91 | ip_address: "10.1.1.21" 92 | state: "absent" 93 | 94 | - name: DELETE SERVER AGAIN - NO CHANGE 95 | netscaler_server: 96 | host: "{{ inventory_hostname }}" 97 | username: "{{ username }}" 98 | password: "{{ password }}" 99 | server_name: "server01" 100 | ip_address: "10.1.1.21" 101 | state: "absent" 102 | 103 | - name: CONFIG SERVER IN TRAFFIC DOMAIN - CHANGE 104 | netscaler_server: 105 | host: "{{ inventory_hostname }}" 106 | username: "{{ username }}" 107 | password: "{{ password }}" 108 | server_name: "server01" 109 | ip_address: "10.1.1.21" 110 | traffic_domain: 10 111 | 112 | - name: CONFIG SERVER IN TRAFFIC DOMAIN WITH DUPLICATE IP FROM DEFAULT TRAFFIC DOMAIN - CHANGE 113 | netscaler_server: 114 | host: "{{ inventory_hostname }}" 115 | username: "{{ username }}" 116 | password: "{{ password }}" 117 | server_name: "server05" 118 | ip_address: "10.1.1.22" 119 | traffic_domain: 10 120 | 121 | - name: SET PROVIDER - NO CHANGE 122 | set_fact: 123 | provider: 124 | host: "{{ inventory_hostname }}" 125 | username: "{{ username }}" 126 | password: "{{ password }}" 127 | server_name: "server01" 128 | ip_address: "10.1.1.21" 129 | traffic_domain: 10 130 | 131 | - name: CONFIG SERVER IN TRAFFIC DOMAIN WITH PROVIDER - NO CHANGE 132 | netscaler_server: 133 | provider: "{{ provider }}" 134 | 135 | - name: CONFIG SERVER OVERRIDE PROVIDER - CHANGE 136 | netscaler_server: 137 | provider: "{{ provider }}" 138 | server_name: "server06" 139 | ip_address: "10.2.1.21" 140 | traffic_domain: 0 141 | 142 | - name: CONFIG SERVER WITHOUT HOST - FAIL 143 | netscaler_server: 144 | username: "{{ username }}" 145 | password: "{{ password }}" 146 | server_name: "server05" 147 | ip_address: "10.1.1.25" 148 | ignore_errors: yes 149 | tags: no_name 150 | 151 | - name: CONFIG SERVER WITHOUT NAME - FAIL 152 | netscaler_server: 153 | host: "{{ inventory_hostname }}" 154 | username: "{{ username }}" 155 | password: "{{ password }}" 156 | ip_address: "10.1.1.25" 157 | ignore_errors: yes 158 | tags: no_name 159 | 160 | - name: CONFIG SERVER WITH DUPLICATE NAME - FAIL 161 | netscaler_server: 162 | host: "{{ inventory_hostname }}" 163 | username: "{{ username }}" 164 | password: "{{ password }}" 165 | server_name: "server04" 166 | ip_address: "10.1.1.100" 167 | ignore_errors: yes 168 | tags: dup_name 169 | 170 | - name: CONFIG SERVER WITH DUPLICATE IP - FAIL 171 | netscaler_server: 172 | host: "{{ inventory_hostname }}" 173 | username: "{{ username }}" 174 | password: "{{ password }}" 175 | server_name: "server25" 176 | ip_address: "10.1.1.24" 177 | ignore_errors: yes 178 | tags: dup_ip 179 | 180 | - name: CONFIG SERVER WITH DUPLICATE NAME OVERRIDE (RE-IP SERVER) - CHANGE 181 | netscaler_server: 182 | host: "{{ inventory_hostname }}" 183 | username: "{{ username }}" 184 | password: "{{ password }}" 185 | server_name: "server04" 186 | ip_address: "10.1.1.100" 187 | config_override: true 188 | tags: dup_name 189 | 190 | - name: CONFIG SERVER WITH DUPLICATE IP OVERRIDE (RE-NAME SERVER) - CHANGE 191 | netscaler_server: 192 | host: "{{ inventory_hostname }}" 193 | username: "{{ username }}" 194 | password: "{{ password }}" 195 | server_name: "server25" 196 | ip_address: "10.1.1.100" 197 | config_override: true 198 | tags: dup_ip 199 | 200 | - name: CONFIG SERVER WITHOUT IP - FAIL 201 | netscaler_server: 202 | host: "{{ inventory_hostname }}" 203 | username: "{{ username }}" 204 | password: "{{ password }}" 205 | server_name: "server05" 206 | ignore_errors: yes 207 | tags: no_ip 208 | 209 | - name: CONFIG SERVER IN PARTITION AND NON-EXISTENT TRAFFIC DOMAIN - FAIL 210 | netscaler_server: 211 | host: "{{ inventory_hostname }}" 212 | username: "{{ username }}" 213 | password: "{{ password }}" 214 | server_name: "server01" 215 | ip_address: "10.1.1.21" 216 | partition: "LAB" 217 | traffic_domain: 10 218 | ignore_errors: yes 219 | tags: bad_td 220 | 221 | - name: CONFIG SERVER IN TRAFFIC DOMAIN WITH DUPLICATE NAME - FAIL 222 | netscaler_server: 223 | host: "{{ inventory_hostname }}" 224 | username: "{{ username }}" 225 | password: "{{ password }}" 226 | server_name: "server01" 227 | ip_address: "10.1.1.100" 228 | traffic_domain: 10 229 | ignore_errors: yes 230 | tags: dup_name_td 231 | 232 | 233 | 234 | - name: UNITTEST CLEANUP 235 | hosts: netscaler 236 | connection: local 237 | gather_facts: False 238 | 239 | tasks: 240 | - name: DELETE SERVERS 241 | netscaler_server: 242 | host: "{{ inventory_hostname }}" 243 | username: "{{ username }}" 244 | password: "{{ password }}" 245 | server_name: "{{ item }}" 246 | state: "absent" 247 | with_items: 248 | - "server01" 249 | - "server03" 250 | - "server04" 251 | - "server05" 252 | - "server06" 253 | - "server25" 254 | tags: cleanup 255 | 256 | - name: DELETE SEVER IN PARTITION 257 | netscaler_server: 258 | host: "{{ inventory_hostname }}" 259 | username: "{{ username }}" 260 | password: "{{ password }}" 261 | server_name: "server02" 262 | partition: "LAB" 263 | state: "absent" 264 | tags: cleanup -------------------------------------------------------------------------------- /unittests/netscaler_servicegroup_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CONFIG SERVICE GROUP - CHANGE 9 | netscaler_servicegroup: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | max_client: 20 14 | max_req: 100 15 | server_timeout: 300 16 | service_type: "tcp" 17 | servicegroup_name: "servicegroup01" 18 | cip: "ENABLED" 19 | cipheader: "header" 20 | cka: "YES" 21 | tcpb: "YES" 22 | usip: "YES" 23 | useproxyport: "YES" 24 | 25 | - name: CONFIG SERVICE GROUP AGAIN - NO CHANGE 26 | netscaler_servicegroup: 27 | host: "{{ inventory_hostname }}" 28 | username: "{{ username }}" 29 | password: "{{ password }}" 30 | max_client: 20 31 | max_req: 100 32 | server_timeout: 300 33 | service_type: "TCP" 34 | servicegroup_name: "servicegroup01" 35 | client_header_state: "enabled" 36 | client_header: "header" 37 | client_keepalive: "yes" 38 | tcp_buffer: "yes" 39 | use_client_ip: "yes" 40 | use_proxy_port: "yes" 41 | 42 | - name: CONFIG SERVICE GROUP AGAIN LESS PARAMS - NO CHANGE 43 | netscaler_servicegroup: 44 | host: "{{ inventory_hostname }}" 45 | username: "{{ username }}" 46 | password: "{{ password }}" 47 | service_type: "TCP" 48 | servicegroup_name: "servicegroup01" 49 | 50 | - name: CONFIG SERVICE GROUP IN PARTITION - CHANGE 51 | netscaler_servicegroup: 52 | host: "{{ inventory_hostname }}" 53 | username: "{{ username }}" 54 | password: "{{ password }}" 55 | max_client: 20 56 | max_req: 100 57 | server_timeout: 300 58 | service_type: "TCP" 59 | servicegroup_name: "servicegroup01" 60 | partition: "LAB" 61 | 62 | - name: CONFIG SERVICE GROUP WITH A COMMENT - CHANGE 63 | netscaler_servicegroup: 64 | host: "{{ inventory_hostname }}" 65 | username: "{{ username }}" 66 | password: "{{ password }}" 67 | service_type: "HTTP" 68 | servicegroup_name: "servicegroup02" 69 | comment: "Comments Work" 70 | 71 | - name: CONFIG SERVICE GROUP IN TRAFFIC DOMAIN - CHANGE 72 | netscaler_servicegroup: 73 | host: "{{ inventory_hostname }}" 74 | username: "{{ username }}" 75 | password: "{{ password }}" 76 | max_client: 20 77 | max_req: 100 78 | server_timeout: 300 79 | service_type: "TCP" 80 | servicegroup_name: "servicegroup03" 81 | traffic_domain: 10 82 | 83 | - name: CONFIG SERVICE GROUP IN A DISABLED STATE - CHANGE 84 | netscaler_servicegroup: 85 | host: "{{ inventory_hostname }}" 86 | username: "{{ username }}" 87 | password: "{{ password }}" 88 | max_client: 20 89 | max_req: 100 90 | server_timeout: 300 91 | service_type: "TCP" 92 | servicegroup_name: "servicegroup04" 93 | servicegroup_state: "disabled" 94 | 95 | - name: MODIFY SERVICE GROUP PARAMS AND COMMENT - CHANGE 96 | netscaler_servicegroup: 97 | host: "{{ inventory_hostname }}" 98 | username: "{{ username }}" 99 | password: "{{ password }}" 100 | max_client: 20 101 | max_req: 100 102 | server_timeout: 300 103 | service_type: "HTTP" 104 | servicegroup_name: "servicegroup02" 105 | comment: "Comments Still Work" 106 | cmp: "yes" 107 | 108 | - name: DISABLE A SERVICE GROUP - CHANGE 109 | netscaler_servicegroup: 110 | host: "{{ inventory_hostname }}" 111 | username: "{{ username }}" 112 | password: "{{ password }}" 113 | servicegroup_name: "servicegroup01" 114 | servicegroup_state: "disabled" 115 | 116 | - name: ENABLE SERVICE GROUP AND MODIFY PARAMS - CHANGE 117 | netscaler_servicegroup: 118 | host: "{{ inventory_hostname }}" 119 | username: "{{ username }}" 120 | password: "{{ password }}" 121 | servicegroup_name: "servicegroup01" 122 | max_client: 30 123 | max_req: 110 124 | servicegroup_state: "enabled" 125 | 126 | - name: DELETE SERVICE GROUP - CHANGE 127 | netscaler_servicegroup: 128 | host: "{{ inventory_hostname }}" 129 | username: "{{ username }}" 130 | password: "{{ password }}" 131 | servicegroup_name: "servicegroup01" 132 | state: "absent" 133 | 134 | - name: DELETE SERVICE GROUP - NO CHANGE 135 | netscaler_servicegroup: 136 | host: "{{ inventory_hostname }}" 137 | username: "{{ username }}" 138 | password: "{{ password }}" 139 | servicegroup_name: "servicegroup01" 140 | state: "absent" 141 | 142 | - name: SET PROVIDER - NO CHANGE 143 | set_fact: 144 | provider: 145 | host: "{{ inventory_hostname }}" 146 | username: "{{ username }}" 147 | password: "{{ password }}" 148 | max_client: 20 149 | max_req: 100 150 | server_timeout: 300 151 | service_type: "TCP" 152 | servicegroup_name: "servicegroup04" 153 | servicegroup_state: "disabled" 154 | 155 | - name: CREATE SERVICE GROUP WITH PROVIDER - NO CHANGE 156 | netscaler_servicegroup: 157 | provider: "{{ provider }}" 158 | 159 | - name: CREATE SERVICE GROUP OVERRIDE PROVIDER - CHANGE 160 | netscaler_servicegroup: 161 | provider: "{{ provider }}" 162 | max_client: 25 163 | max_req: 200 164 | server_timeout: 400 165 | service_type: "HTTP" 166 | servicegroup_name: "servicegroup05" 167 | servicegroup_state: "enabled" 168 | 169 | - name: CONFIG SERVICE GROUP WITHOUT A NAME - FAIL 170 | netscaler_servicegroup: 171 | host: "{{ inventory_hostname }}" 172 | username: "{{ username }}" 173 | password: "{{ password }}" 174 | service_type: "HTTP" 175 | ignore_errors: yes 176 | tags: no_name 177 | 178 | - name: CONFIG SERVICE GROUP WITHOUT A HOST - FAIL 179 | netscaler_servicegroup: 180 | username: "{{ username }}" 181 | password: "{{ password }}" 182 | servicegroup_name: "servicegroup10" 183 | service_type: "HTTP" 184 | ignore_errors: yes 185 | tags: no_name 186 | 187 | - name: MODIFY SERVICE GROUP IN TRAFFIC DOMAIN - FAIL 188 | netscaler_servicegroup: 189 | host: "{{ inventory_hostname }}" 190 | username: "{{ username }}" 191 | password: "{{ password }}" 192 | servicegroup_name: "servicegroup03" 193 | service_type: "HTTP" 194 | ignore_errors: true 195 | 196 | - name: MODIFY SERVICE GROUP IN TRAFFIC DOMAIN - FAIL 197 | netscaler_servicegroup: 198 | host: "{{ inventory_hostname }}" 199 | username: "{{ username }}" 200 | password: "{{ password }}" 201 | servicegroup_name: "servicegroup03" 202 | traffic_domain: 0 203 | ignore_errors: true 204 | 205 | - name: CONFIG SERVICE GROUP WITHOUT A SERVICE TYPE - FAIL 206 | netscaler_servicegroup: 207 | host: "{{ inventory_hostname }}" 208 | username: "{{ username }}" 209 | password: "{{ password }}" 210 | servicegroup_name: "servicegroup10" 211 | ignore_errors: yes 212 | tags: no_type 213 | 214 | - name: CONFIG SERVICE GROUP DUPLICATE NAME - FAIL 215 | netscaler_servicegroup: 216 | host: "{{ inventory_hostname }}" 217 | username: "{{ username }}" 218 | password: "{{ password }}" 219 | service_type: "TCP" 220 | servicegroup_name: "servicegroup02" 221 | ignore_errors: yes 222 | tags: dup_name 223 | 224 | - name: CONFIG SERVICE GROUP IN NON-EXISTENT TRAFFIC DOMAIN - FAIL 225 | netscaler_servicegroup: 226 | host: "{{ inventory_hostname }}" 227 | username: "{{ username }}" 228 | password: "{{ password }}" 229 | service_type: "TCP" 230 | servicegroup_name: "servicegroup01" 231 | traffic_domain: 20 232 | ignore_errors: yes 233 | tags: bad_td 234 | 235 | - name: CONFIG SERVICE GROUP WITH INVALID SERICE TYPE - FAIL 236 | netscaler_servicegroup: 237 | host: "{{ inventory_hostname }}" 238 | username: "{{ username }}" 239 | password: "{{ password }}" 240 | service_type: "FAKE" 241 | servicegroup_name: "servicegroup01" 242 | ignore_errors: yes 243 | tags: bad_type 244 | 245 | - name: CONFIG SERVICE GROUP WITH INVALID MAX CLIENT - FAIL 246 | netscaler_servicegroup: 247 | host: "{{ inventory_hostname }}" 248 | username: "{{ username }}" 249 | password: "{{ password }}" 250 | max_client: 2000000000000000000 251 | service_type: "TCP" 252 | servicegroup_name: "servicegroup01" 253 | ignore_errors: yes 254 | tags: bad_max 255 | 256 | 257 | 258 | - name: UNITTEST CLEANUP 259 | hosts: netscaler 260 | connection: local 261 | gather_facts: False 262 | 263 | tasks: 264 | - name: CLEANUP SERVICE GROUP - CHANGE 265 | netscaler_servicegroup: 266 | host: "{{ inventory_hostname }}" 267 | username: "{{ username }}" 268 | password: "{{ password }}" 269 | state: "absent" 270 | servicegroup_name: "{{ item }}" 271 | with_items: 272 | - "servicegroup01" 273 | - "servicegroup02" 274 | - "servicegroup03" 275 | - "servicegroup04" 276 | - "servicegroup05" 277 | tags: cleanup 278 | 279 | - name: CLEANUP SERVICE GROUP IN PARTITION - CHANGE 280 | netscaler_servicegroup: 281 | host: "{{ inventory_hostname }}" 282 | username: "{{ username }}" 283 | password: "{{ password }}" 284 | state: "absent" 285 | servicegroup_name: "servicegroup01" 286 | partition: "LAB" 287 | tags: cleanup -------------------------------------------------------------------------------- /unittests/netscaler_servicegroup_monitor_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PREPARE OBJECTS 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CREATE MONITORS - CHANGE 9 | netscaler_lbmonitor: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | monitor_name: "{{ item.name }}" 14 | monitor_type: HTTP 15 | partition: "{{ item.partition | default('default') }}" 16 | with_items: 17 | - name: "monitor01" 18 | - name: "monitor02" 19 | - name: "monitor01" 20 | partition: "LAB" 21 | 22 | - name: CREATE SERVICE GROUPS - CHANGE 23 | netscaler_servicegroup: 24 | host: "{{ inventory_hostname }}" 25 | username: "{{ username }}" 26 | password: "{{ password }}" 27 | servicegroup_name: "{{ item.servicegroup }}" 28 | service_type: HTTP 29 | partition: "{{ item.partition | default('default')}}" 30 | with_items: 31 | - servicegroup: "servicegroup01" 32 | - servicegroup: "servicegroup02" 33 | - servicegroup: "servicegroup01" 34 | partition: "LAB" 35 | 36 | 37 | - name: UNITTEST 38 | hosts: netscaler 39 | connection: local 40 | gather_facts: False 41 | 42 | tasks: 43 | - name: CREATE SERVICE GROUP TO MONITOR BINDING - CHANGE 44 | netscaler_servicegroup_monitor: 45 | host: "{{ inventory_hostname }}" 46 | username: "{{ username }}" 47 | password: "{{ password }}" 48 | monitor_name: "monitor01" 49 | servicegroup_name: "servicegroup01" 50 | 51 | - name: CREATE SERVICE GROUP TO MONITOR BINDING AGAIN - NO CHANGE 52 | netscaler_servicegroup_monitor: 53 | host: "{{ inventory_hostname }}" 54 | username: "{{ username }}" 55 | password: "{{ password }}" 56 | monitor_name: "monitor01" 57 | servicegroup_name: "servicegroup01" 58 | 59 | - name: CREATE SERVICE GROUP TO MONITOR BINDING IN DISABLED STATE - CHANGE 60 | netscaler_servicegroup_monitor: 61 | host: "{{ inventory_hostname }}" 62 | username: "{{ username }}" 63 | password: "{{ password }}" 64 | monitor_name: "monitor02" 65 | servicegroup_name: "servicegroup01" 66 | monitor_state: "disabled" 67 | 68 | - name: CREATE SERVICE GROUP TO MONITOR BINDING IN PARTITION - CHANGE 69 | netscaler_servicegroup_monitor: 70 | host: "{{ inventory_hostname }}" 71 | username: "{{ username }}" 72 | password: "{{ password }}" 73 | monitor_name: "monitor01" 74 | servicegroup_name: "servicegroup01" 75 | partition: "LAB" 76 | 77 | - name: CREATE SERVICE GROUP TO MONITOR BINDING WITH WEIGHT - CHANGE 78 | netscaler_servicegroup_monitor: 79 | host: "{{ inventory_hostname }}" 80 | username: "{{ username }}" 81 | password: "{{ password }}" 82 | monitor_name: "monitor02" 83 | servicegroup_name: "servicegroup02" 84 | weight: "20" 85 | 86 | - name: CREATE SERVICE GROUP TO MONITOR BINDING WITH WEIGHT AGAIN - NO CHANGE 87 | netscaler_servicegroup_monitor: 88 | host: "{{ inventory_hostname }}" 89 | username: "{{ username }}" 90 | password: "{{ password }}" 91 | monitor_name: "monitor02" 92 | servicegroup_name: "servicegroup02" 93 | weight: "20" 94 | 95 | - name: DISABLE SERVICE GROUP TO MONITOR BINDING - CHANGE 96 | netscaler_servicegroup_monitor: 97 | host: "{{ inventory_hostname }}" 98 | username: "{{ username }}" 99 | password: "{{ password }}" 100 | monitor_name: "monitor02" 101 | servicegroup_name: "servicegroup02" 102 | monitor_state: "disabled" 103 | 104 | - name: DISABLE SERVICE GROUP TO MONITOR BINDING AGAIN - NO CHANGE 105 | netscaler_servicegroup_monitor: 106 | host: "{{ inventory_hostname }}" 107 | username: "{{ username }}" 108 | password: "{{ password }}" 109 | monitor_name: "monitor02" 110 | servicegroup_name: "servicegroup02" 111 | monitor_state: "disabled" 112 | 113 | - name: ENABLE SERVICE GROUP TO MONITOR BINDING - CHANGE 114 | netscaler_servicegroup_monitor: 115 | host: "{{ inventory_hostname }}" 116 | username: "{{ username }}" 117 | password: "{{ password }}" 118 | monitor_name: "monitor02" 119 | servicegroup_name: "servicegroup02" 120 | monitor_state: "enabled" 121 | 122 | - name: REMOVE SERVICE GROUP TO MONITOR BINDING - CHANGE 123 | netscaler_servicegroup_monitor: 124 | host: "{{ inventory_hostname }}" 125 | username: "{{ username }}" 126 | password: "{{ password }}" 127 | monitor_name: "monitor01" 128 | servicegroup_name: "servicegroup01" 129 | partition: "LAB" 130 | state: "absent" 131 | 132 | - name: REMOVE SERVICE GROUP TO MONITOR BINDING AGAIN - NO CHANGE 133 | netscaler_servicegroup_monitor: 134 | host: "{{ inventory_hostname }}" 135 | username: "{{ username }}" 136 | password: "{{ password }}" 137 | monitor_name: "monitor01" 138 | servicegroup_name: "servicegroup01" 139 | partition: "LAB" 140 | state: "absent" 141 | 142 | - name: SET PROVIDER - NO CHANGE 143 | set_fact: 144 | provider: 145 | host: "{{ inventory_hostname }}" 146 | username: "{{ username }}" 147 | password: "{{ password }}" 148 | monitor_name: "monitor02" 149 | servicegroup_name: "servicegroup02" 150 | weight: "20" 151 | 152 | - name: CREATE SERVICE GROUP TO MONITOR BINDING WITH PROVIDER - NO CHANGE 153 | netscaler_servicegroup_monitor: 154 | provider: "{{ provider }}" 155 | 156 | - name: CREATE SERVICE GROUP TO MONITOR BINDING OVERRIDE PROVIDER - CHANGE 157 | netscaler_servicegroup_monitor: 158 | provider: "{{ provider }}" 159 | monitor_name: "monitor01" 160 | servicegroup_name: "servicegroup02" 161 | weight: "30" 162 | 163 | - name: CREATE SERVICE GROUP TO MONITOR BINDING NO HOST - FAIL 164 | netscaler_servicegroup_monitor: 165 | username: "{{ username }}" 166 | password: "{{ password }}" 167 | servicegroup_name: "servicegroup01" 168 | monitor_name: "monitor01" 169 | ignore_errors: yes 170 | 171 | - name: CREATE SERVICE GROUP TO MONITOR BINDING NO MONITOR NAME - FAIL 172 | netscaler_servicegroup_monitor: 173 | host: "{{ inventory_hostname }}" 174 | username: "{{ username }}" 175 | password: "{{ password }}" 176 | servicegroup_name: "servicegroup01" 177 | ignore_errors: yes 178 | 179 | - name: CREATE SERVICE GROUP TO MONITOR BINDING NO SERVICE GROUP NAME - FAIL 180 | netscaler_servicegroup_monitor: 181 | host: "{{ inventory_hostname }}" 182 | username: "{{ username }}" 183 | password: "{{ password }}" 184 | monitor_name: "monitor01" 185 | ignore_errors: yes 186 | 187 | - name: MODIFY SERVICE GROUP TO MONITOR BINDING - FAIL 188 | netscaler_servicegroup_monitor: 189 | host: "{{ inventory_hostname }}" 190 | username: "{{ username }}" 191 | password: "{{ password }}" 192 | monitor_name: "monitor02" 193 | servicegroup_name: "servicegroup02" 194 | weight: "30" 195 | ignore_errors: true 196 | 197 | - name: CREATE SERVICE GROUP TO MONITOR BINDING MONITOR DOES NOT EXIST - FAIL 198 | netscaler_servicegroup_monitor: 199 | host: "{{ inventory_hostname }}" 200 | username: "{{ username }}" 201 | password: "{{ password }}" 202 | monitor_name: "monitor" 203 | servicegroup_name: "servicegroup01" 204 | ignore_errors: yes 205 | 206 | - name: CREATE SERVICE GROUP TO MONITOR BINDING SERVICE GROUP DOES NOT EXIST - FAIL 207 | netscaler_servicegroup_monitor: 208 | host: "{{ inventory_hostname }}" 209 | username: "{{ username }}" 210 | password: "{{ password }}" 211 | monitor_name: "monitor01" 212 | servicegroup_name: "servicegroup" 213 | ignore_errors: yes 214 | 215 | 216 | 217 | - name: UNITTEST CLEANUP 218 | hosts: netscaler 219 | connection: local 220 | gather_facts: False 221 | tags: cleanup 222 | 223 | tasks: 224 | - name: CLEANUP BINDINGS - CHANGE 225 | netscaler_servicegroup_monitor: 226 | host: "{{ inventory_hostname }}" 227 | username: "{{ username }}" 228 | password: "{{ password }}" 229 | state: "absent" 230 | monitor_name: "{{ item.monitor }}" 231 | servicegroup_name: "{{ item.servicegroup }}" 232 | partition: "{{ item.partition | default('default') }}" 233 | with_items: 234 | - monitor: "monitor01" 235 | servicegroup: "servicegroup01" 236 | - monitor: "monitor02" 237 | servicegroup: "servicegroup01" 238 | - monitor: "monitor02" 239 | servicegroup: "servicegroup02" 240 | - monitor: "monitor01" 241 | servicegroup: "servicegroup02" 242 | - monitor: "monitor01" 243 | servicegroup: "servicegroup01" 244 | partition: "LAB" 245 | 246 | 247 | 248 | - name: PREPARE OBJECTS CLEANUP 249 | hosts: netscaler 250 | connection: local 251 | gather_facts: False 252 | tags: cleanup 253 | 254 | tasks: 255 | - name: CLEANUP MONITORS - CHANGE 256 | netscaler_lbmonitor: 257 | host: "{{ inventory_hostname }}" 258 | username: "{{ username }}" 259 | password: "{{ password }}" 260 | monitor_name: "{{ item.name }}" 261 | partition: "{{ item.partition | default('default') }}" 262 | state: "absent" 263 | with_items: 264 | - name: "monitor01" 265 | - name: "monitor02" 266 | - name: "monitor01" 267 | partition: "LAB" 268 | 269 | - name: CLEANUP SERVICE GROUPS - CHANGE 270 | netscaler_servicegroup: 271 | host: "{{ inventory_hostname }}" 272 | username: "{{ username }}" 273 | password: "{{ password }}" 274 | servicegroup_name: "{{ item.servicegroup }}" 275 | service_type: HTTP 276 | partition: "{{ item.partition | default('default')}}" 277 | state: "absent" 278 | with_items: 279 | - servicegroup: "servicegroup01" 280 | - servicegroup: "servicegroup02" 281 | - servicegroup: "servicegroup01" 282 | partition: "LAB" -------------------------------------------------------------------------------- /unittests/netscaler_servicegroup_server_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: PREPARE OBJECTS 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CREATE SERVERS - CHANGE 9 | netscaler_server: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | server_name: "{{ item.name }}" 14 | ip_address: "{{ item.ip }}" 15 | partition: "{{ item.partition | default('default') }}" 16 | with_items: 17 | - name: "server01" 18 | ip: "10.1.1.21" 19 | - name: "server02" 20 | ip: "10.1.1.22" 21 | - name: "server01" 22 | ip: "10.1.1.21" 23 | partition: "LAB" 24 | 25 | - name: CREATE SERVICE GROUPS - CHANGE 26 | netscaler_servicegroup: 27 | host: "{{ inventory_hostname }}" 28 | username: "{{ username }}" 29 | password: "{{ password }}" 30 | servicegroup_name: "{{ item.servicegroup }}" 31 | service_type: HTTP 32 | partition: "{{ item.partition | default('default')}}" 33 | with_items: 34 | - servicegroup: "servicegroup01" 35 | - servicegroup: "servicegroup02" 36 | - servicegroup: "servicegroup01" 37 | partition: "LAB" 38 | 39 | 40 | - name: UNITTEST 41 | hosts: netscaler 42 | connection: local 43 | gather_facts: False 44 | 45 | tasks: 46 | - name: CREATE SERVICE GROUP TO SERVER BINDING - CHANGE 47 | netscaler_servicegroup_server: 48 | host: "{{ inventory_hostname }}" 49 | username: "{{ username }}" 50 | password: "{{ password }}" 51 | server_name: "server01" 52 | servicegroup_name: "servicegroup01" 53 | server_port: 80 54 | 55 | - name: CREATE SERVICE GROUP TO SERVER BINDING AGAIN - NO CHANGE 56 | netscaler_servicegroup_server: 57 | host: "{{ inventory_hostname }}" 58 | username: "{{ username }}" 59 | password: "{{ password }}" 60 | server_name: "server01" 61 | servicegroup_name: "servicegroup01" 62 | server_port: 80 63 | 64 | - name: CREATE SERVICE GROUP TO SERVER BINDING WITH WEIGHT - CHANGE 65 | netscaler_servicegroup_server: 66 | host: "{{ inventory_hostname }}" 67 | username: "{{ username }}" 68 | password: "{{ password }}" 69 | server_name: "server02" 70 | servicegroup_name: "servicegroup02" 71 | server_port: 80 72 | weight: "20" 73 | 74 | - name: CREATE SERVICE GROUP TO SERVER BINDING WITH WEIGHT AGAIN - NO CHANGE 75 | netscaler_servicegroup_server: 76 | host: "{{ inventory_hostname }}" 77 | username: "{{ username }}" 78 | password: "{{ password }}" 79 | server_name: "server02" 80 | servicegroup_name: "servicegroup02" 81 | server_port: 80 82 | weight: "20" 83 | 84 | - name: ADD SERVICE GROUP TO SERVER BINDING WITH NEW PORT - CHANGE 85 | netscaler_servicegroup_server: 86 | host: "{{ inventory_hostname }}" 87 | username: "{{ username }}" 88 | password: "{{ password }}" 89 | server_name: "server01" 90 | servicegroup_name: "servicegroup01" 91 | server_port: 443 92 | 93 | - name: CREATE SERVICE GROUP TO SERVER BINDING IN PARTITION - CHANGE 94 | netscaler_servicegroup_server: 95 | host: "{{ inventory_hostname }}" 96 | username: "{{ username }}" 97 | password: "{{ password }}" 98 | server_name: "server01" 99 | servicegroup_name: "servicegroup01" 100 | server_port: 80 101 | partition: "LAB" 102 | 103 | - name: REMOVE SERVICE GROUP TO SERVER BINDING - CHANGE 104 | netscaler_servicegroup_server: 105 | host: "{{ inventory_hostname }}" 106 | username: "{{ username }}" 107 | password: "{{ password }}" 108 | server_name: "server01" 109 | servicegroup_name: "servicegroup01" 110 | server_port: 80 111 | partition: "LAB" 112 | state: "absent" 113 | 114 | - name: REMOVE SERVICE GROUP TO SERVER BINDING AGAIN - NO CHANGE 115 | netscaler_servicegroup_server: 116 | host: "{{ inventory_hostname }}" 117 | username: "{{ username }}" 118 | password: "{{ password }}" 119 | server_name: "server01" 120 | servicegroup_name: "servicegroup01" 121 | server_port: 80 122 | partition: "LAB" 123 | state: "absent" 124 | 125 | - name: SET PROIVDER - NO CHANGE 126 | set_fact: 127 | provider: 128 | host: "{{ inventory_hostname }}" 129 | username: "{{ username }}" 130 | password: "{{ password }}" 131 | server_name: "server02" 132 | servicegroup_name: "servicegroup02" 133 | server_port: 80 134 | weight: "20" 135 | 136 | - name: CREATE SERVICE GROUP TO SERVER BINDING WITH PROIVDER - NO CHANGE 137 | netscaler_servicegroup_server: 138 | provider: "{{ provider }}" 139 | 140 | - name: CREATE SERVICE GROUP TO SERVER BINDING OVERRIDE PROIVDER - CHANGE 141 | netscaler_servicegroup_server: 142 | provider: "{{ provider }}" 143 | server_name: "server02" 144 | servicegroup_name: "servicegroup01" 145 | server_port: 88 146 | weight: "30" 147 | 148 | - name: CREATE SERVICE GROUP TO SERVER BINDING NO HOST - FAIL 149 | netscaler_servicegroup_server: 150 | username: "{{ username }}" 151 | password: "{{ password }}" 152 | server_name: "server01" 153 | servicegroup_name: "servicegroup01" 154 | server_port: 80 155 | ignore_errors: yes 156 | 157 | - name: CREATE SERVICE GROUP TO SERVER BINDING NO SERVER_NAME - FAIL 158 | netscaler_servicegroup_server: 159 | host: "{{ inventory_hostname }}" 160 | username: "{{ username }}" 161 | password: "{{ password }}" 162 | servicegroup_name: "servicegroup01" 163 | server_port: 80 164 | ignore_errors: yes 165 | 166 | - name: CREATE SERVICE GROUP TO SERVER BINDING NO SERVICEGROUP_NAME - FAIL 167 | netscaler_servicegroup_server: 168 | host: "{{ inventory_hostname }}" 169 | username: "{{ username }}" 170 | password: "{{ password }}" 171 | server_name: "server01" 172 | server_port: 80 173 | ignore_errors: yes 174 | 175 | - name: CREATE SERVICE GROUP TO SERVER BINDING NO PORT - FAIL 176 | netscaler_servicegroup_server: 177 | host: "{{ inventory_hostname }}" 178 | username: "{{ username }}" 179 | password: "{{ password }}" 180 | server_name: "server01" 181 | servicegroup_name: "servicegroup01" 182 | ignore_errors: yes 183 | 184 | - name: CREATE SERVICE GROUP TO SERVER BINDING INVALID PORT - FAIL 185 | netscaler_servicegroup_server: 186 | host: "{{ inventory_hostname }}" 187 | username: "{{ username }}" 188 | password: "{{ password }}" 189 | server_name: "server01" 190 | servicegroup_name: "servicegroup01" 191 | server_port: "BAD" 192 | ignore_errors: yes 193 | 194 | - name: MODIFY SERVICE GROUP TO SERVER BINDING WITH WEIGHT - FAIL 195 | netscaler_servicegroup_server: 196 | host: "{{ inventory_hostname }}" 197 | username: "{{ username }}" 198 | password: "{{ password }}" 199 | server_name: "server02" 200 | servicegroup_name: "servicegroup02" 201 | server_port: 80 202 | weight: "30" 203 | ignore_errors: true 204 | 205 | - name: CREATE SERVICE GROUP TO SERVER BINDING SERVER DOES NOT EXIST - FAIL 206 | netscaler_servicegroup_server: 207 | host: "{{ inventory_hostname }}" 208 | username: "{{ username }}" 209 | password: "{{ password }}" 210 | server_name: "server" 211 | servicegroup_name: "servicegroup01" 212 | server_port: 80 213 | ignore_errors: yes 214 | 215 | - name: CREATE SERVICE GROUP TO SERVER BINDING SERVICE GROUP DOES NOT EXIST - FAIL 216 | netscaler_servicegroup_server: 217 | host: "{{ inventory_hostname }}" 218 | username: "{{ username }}" 219 | password: "{{ password }}" 220 | server_name: "server01" 221 | servicegroup_name: "servicegroup" 222 | server_port: 80 223 | ignore_errors: yes 224 | 225 | 226 | 227 | - name: UNITTEST CLEANUP 228 | hosts: netscaler 229 | connection: local 230 | gather_facts: False 231 | tags: cleanup 232 | 233 | tasks: 234 | - name: CLEANUP BINDINGS - CHANGE 235 | netscaler_servicegroup_server: 236 | host: "{{ inventory_hostname }}" 237 | username: "{{ username }}" 238 | password: "{{ password }}" 239 | state: "absent" 240 | server_name: "{{ item.server }}" 241 | servicegroup_name: "{{ item.servicegroup }}" 242 | server_port: "{{ item.port }}" 243 | partition: "{{ item.partition | default('default') }}" 244 | with_items: 245 | - server: "server01" 246 | servicegroup: "servicegroup01" 247 | port: 80 248 | - server: "server01" 249 | servicegroup: "servicegroup01" 250 | port: 443 251 | - server: "server01" 252 | servicegroup: "servicegroup01" 253 | port: 80 254 | partition: "LAB" 255 | - server: "server02" 256 | servicegroup: "servicegroup02" 257 | port: 80 258 | - server: "server02" 259 | servicegroup: "servicegroup01" 260 | port: 88 261 | 262 | 263 | - name: PREPARE OBJECTS CLEANUP 264 | hosts: netscaler 265 | connection: local 266 | gather_facts: False 267 | tags: cleanup 268 | 269 | tasks: 270 | - name: CLEANUP SERVERS - CHANGE 271 | netscaler_server: 272 | host: "{{ inventory_hostname }}" 273 | username: "{{ username }}" 274 | password: "{{ password }}" 275 | server_name: "{{ item.name }}" 276 | ip_address: "{{ item.ip }}" 277 | partition: "{{ item.partition | default('default') }}" 278 | state: "absent" 279 | with_items: 280 | - name: "server01" 281 | ip: "10.1.1.21" 282 | - name: "server02" 283 | ip: "10.1.1.22" 284 | - name: "server01" 285 | ip: "10.1.1.21" 286 | partition: "LAB" 287 | 288 | - name: CLEANUP SERVICE GROUPS - CHANGE 289 | netscaler_servicegroup: 290 | host: "{{ inventory_hostname }}" 291 | username: "{{ username }}" 292 | password: "{{ password }}" 293 | servicegroup_name: "{{ item.servicegroup }}" 294 | service_type: HTTP 295 | partition: "{{ item.partition | default('default')}}" 296 | state: "absent" 297 | with_items: 298 | - servicegroup: "servicegroup01" 299 | - servicegroup: "servicegroup02" 300 | - servicegroup: "servicegroup01" 301 | partition: "LAB" -------------------------------------------------------------------------------- /unittests/netscaler_lbmonitor_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CREATE TCP MONITOR - CHANGE 9 | netscaler_lbmonitor: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | monitor_name: "monitor01" 14 | monitor_type: "tcp" 15 | monitor_dest_ip: "10.10.10.10" 16 | monitor_dest_port: "22" 17 | lrtm: "enabled" 18 | interval: 8 19 | retries: 3 20 | resptimeout: 5 21 | 22 | - name: CREATE TCP MONITOR AGAIN - NO CHANGE 23 | netscaler_lbmonitor: 24 | host: "{{ inventory_hostname }}" 25 | username: "{{ username }}" 26 | password: "{{ password }}" 27 | monitor_name: "monitor01" 28 | monitor_type: "TCP" 29 | monitor_dest_ip: "10.10.10.10" 30 | monitor_dest_port: "22" 31 | least_response_time: "enabled" 32 | probe_interval: 8 33 | probe_retries: 3 34 | probe_timeout: 5 35 | 36 | - name: CREATE TCP MONITOR AGAIN LESS PARAMS - NO CHANGE 37 | netscaler_lbmonitor: 38 | host: "{{ inventory_hostname }}" 39 | username: "{{ username }}" 40 | password: "{{ password }}" 41 | monitor_name: "monitor01" 42 | monitor_type: "TCP" 43 | 44 | - name: DISABLE TCP MONITOR - CHANGE 45 | netscaler_lbmonitor: 46 | host: "{{ inventory_hostname }}" 47 | username: "{{ username }}" 48 | password: "{{ password }}" 49 | monitor_name: "monitor01" 50 | monitor_state: "disabled" 51 | 52 | - name: DISABLE TCP MONITOR AGAIN - NO CHANGE 53 | netscaler_lbmonitor: 54 | host: "{{ inventory_hostname }}" 55 | username: "{{ username }}" 56 | password: "{{ password }}" 57 | monitor_name: "monitor01" 58 | monitor_state: "disabled" 59 | 60 | - name: ENABLE TCP MONITOR - CHANGE 61 | netscaler_lbmonitor: 62 | host: "{{ inventory_hostname }}" 63 | username: "{{ username }}" 64 | password: "{{ password }}" 65 | monitor_name: "monitor01" 66 | monitor_state: "enabled" 67 | 68 | - name: CREATE HTTP MONITOR - CHANGE 69 | netscaler_lbmonitor: 70 | host: "{{ inventory_hostname }}" 71 | username: "{{ username }}" 72 | password: "{{ password }}" 73 | monitor_name: "monitor02" 74 | http_request: "HEAD /healthceck.html" 75 | monitor_type: "http" 76 | monitor_use_ssl: "yes" 77 | response_code: "200-202" 78 | 79 | - name: CREATE HTTP MONITOR AGAIN - NO CHANGE 80 | netscaler_lbmonitor: 81 | host: "{{ inventory_hostname }}" 82 | username: "{{ username }}" 83 | password: "{{ password }}" 84 | monitor_name: "monitor02" 85 | http_request: "HEAD /healthceck.html" 86 | monitor_type: "HTTP" 87 | monitor_use_ssl: "YES" 88 | response_code: "200-202" 89 | 90 | - name: SET PROVIDER - NO CHANGE 91 | set_fact: 92 | provider: 93 | host: "{{ inventory_hostname }}" 94 | username: "{{ username }}" 95 | password: "{{ password }}" 96 | monitor_name: "monitor02" 97 | http_request: "HEAD /healthceck.html" 98 | monitor_type: "http" 99 | monitor_use_ssl: "yes" 100 | response_code: "200-202" 101 | 102 | - name: CREATE HTTP MONITOR WITH PROVIDER - NO CHANGE 103 | netscaler_lbmonitor: 104 | provider: "{{ provider }}" 105 | 106 | - name: CREATE HTTP MONITOR OVERRIDE PROVIDER - CHANGE 107 | netscaler_lbmonitor: 108 | provider: "{{ provider }}" 109 | monitor_name: "monitor03" 110 | http_request: "HEAD /health.html" 111 | monitor_type: "http" 112 | monitor_use_ssl: "no" 113 | response_code: 203 114 | 115 | - name: CREATE HTTP MONITOR AGAIN LESS PARAMS - NO CHANGE 116 | netscaler_lbmonitor: 117 | host: "{{ inventory_hostname }}" 118 | username: "{{ username }}" 119 | password: "{{ password }}" 120 | monitor_name: "monitor02" 121 | http_request: "HEAD /healthceck.html" 122 | monitor_type: "HTTP" 123 | 124 | - name: MODIFY HTTP MONITOR - CHANGE 125 | netscaler_lbmonitor: 126 | host: "{{ inventory_hostname }}" 127 | username: "{{ username }}" 128 | password: "{{ password }}" 129 | monitor_name: "monitor02" 130 | http_request: "HEAD /health.html" 131 | monitor_type: "HTTP" 132 | monitor_use_ssl: "NO" 133 | 134 | - name: ADD RESPONSE CODE TO HTTP MONITOR - CHANGE 135 | netscaler_lbmonitor: 136 | host: "{{ inventory_hostname }}" 137 | username: "{{ username }}" 138 | password: "{{ password }}" 139 | monitor_name: "monitor02" 140 | response_code: 205 141 | 142 | - name: ADD RESPONSE CODES TO HTTP MONITOR STRING - CHANGE 143 | netscaler_lbmonitor: 144 | host: "{{ inventory_hostname }}" 145 | username: "{{ username }}" 146 | password: "{{ password }}" 147 | monitor_name: "monitor02" 148 | response_code: "207-210, 212" 149 | 150 | - name: ADD RESPONSE CODES TO HTTP MONITOR LIST - CHANGE 151 | netscaler_lbmonitor: 152 | host: "{{ inventory_hostname }}" 153 | username: "{{ username }}" 154 | password: "{{ password }}" 155 | monitor_name: "monitor02" 156 | response_code: 157 | - "214-217" 158 | - "219" 159 | - "222-230" 160 | 161 | - name: ADD RESPONSE CODES THAT EXIST - NO CHANGE 162 | netscaler_lbmonitor: 163 | host: "{{ inventory_hostname }}" 164 | username: "{{ username }}" 165 | password: "{{ password }}" 166 | monitor_name: "monitor02" 167 | response_code: "207-210, 212" 168 | 169 | - name: REMOVE RESPONSE CODE FROM HTTP MONITOR - CHANGE 170 | netscaler_lbmonitor: 171 | host: "{{ inventory_hostname }}" 172 | username: "{{ username }}" 173 | password: "{{ password }}" 174 | monitor_name: "monitor02" 175 | response_code: 205 176 | response_code_action: remove 177 | 178 | - name: REMOVE RESPONSE CODES FROM HTTP MONITOR STRING - CHANGE 179 | netscaler_lbmonitor: 180 | host: "{{ inventory_hostname }}" 181 | username: "{{ username }}" 182 | password: "{{ password }}" 183 | monitor_name: "monitor02" 184 | response_code: "207-210, 212" 185 | response_code_action: remove 186 | 187 | - name: REMOVE RESPONSE CODES THAT DO NOT EXIST - NO CHANGE 188 | netscaler_lbmonitor: 189 | host: "{{ inventory_hostname }}" 190 | username: "{{ username }}" 191 | password: "{{ password }}" 192 | monitor_name: "monitor02" 193 | response_code: "207-210, 212" 194 | response_code_action: remove 195 | 196 | - name: REMOVE RESPONSE CODES FROM HTTP MONITOR LIST - CHANGE 197 | netscaler_lbmonitor: 198 | host: "{{ inventory_hostname }}" 199 | username: "{{ username }}" 200 | password: "{{ password }}" 201 | monitor_name: "monitor02" 202 | response_code: 203 | - "214-217" 204 | - "219" 205 | response_code_action: remove 206 | 207 | - name: ADD RESPONSE CODES THAT EXIST INSIDE A RANGE - NO CHANGE 208 | netscaler_lbmonitor: 209 | host: "{{ inventory_hostname }}" 210 | username: "{{ username }}" 211 | password: "{{ password }}" 212 | monitor_name: "monitor02" 213 | response_code: "223-226" 214 | 215 | - name: REMOVE RESPONSE CODES INSIDE A RANGE - CHANGE 216 | netscaler_lbmonitor: 217 | host: "{{ inventory_hostname }}" 218 | username: "{{ username }}" 219 | password: "{{ password }}" 220 | monitor_name: "monitor02" 221 | response_code: "223-225" 222 | response_code_action: remove 223 | 224 | - name: CREATE PING MONITOR IN PARTITION - CHANGE 225 | netscaler_lbmonitor: 226 | host: "{{ inventory_hostname }}" 227 | username: "{{ username }}" 228 | password: "{{ password }}" 229 | monitor_name: "monitor01" 230 | monitor_type: "PING" 231 | partition: "LAB" 232 | 233 | - name: CREATE ECV MONITOR - CHANGE 234 | netscaler_lbmonitor: 235 | host: "{{ inventory_hostname }}" 236 | username: "{{ username }}" 237 | password: "{{ password }}" 238 | monitor_name: "monitor06" 239 | monitor_type: "tcp-ecv" 240 | recv: "healthy" 241 | send: "health check" 242 | 243 | - name: CREATE ECV MONITOR - NO CHANGE 244 | netscaler_lbmonitor: 245 | host: "{{ inventory_hostname }}" 246 | username: "{{ username }}" 247 | password: "{{ password }}" 248 | monitor_name: "monitor06" 249 | monitor_type: "tcp-ecv" 250 | ecv_recv: "healthy" 251 | ecv_send: "health check" 252 | 253 | - name: MODIFY ECV MONITOR - CHANGE 254 | netscaler_lbmonitor: 255 | host: "{{ inventory_hostname }}" 256 | username: "{{ username }}" 257 | password: "{{ password }}" 258 | monitor_name: "monitor06" 259 | monitor_type: "tcp-ecv" 260 | ecv_recv: "changed" 261 | ecv_send: "changed" 262 | 263 | - name: CREATE MONITOR NO HOST - FAIL 264 | netscaler_lbmonitor: 265 | username: "{{ username }}" 266 | password: "{{ password }}" 267 | monitor_name: "monitor02" 268 | monitor_type: "TCP" 269 | ignore_errors: true 270 | 271 | - name: CREATE MONITOR NO NAME - FAIL 272 | netscaler_lbmonitor: 273 | host: "{{ inventory_hostname }}" 274 | username: "{{ username }}" 275 | password: "{{ password }}" 276 | monitor_type: "TCP" 277 | ignore_errors: true 278 | 279 | - name: MODIFY MONITOR TYPE - FAIL 280 | netscaler_lbmonitor: 281 | host: "{{ inventory_hostname }}" 282 | username: "{{ username }}" 283 | password: "{{ password }}" 284 | monitor_name: "monitor02" 285 | monitor_type: "TCP" 286 | ignore_errors: true 287 | 288 | - name: DELETE MONITOR - CHANGE 289 | netscaler_lbmonitor: 290 | host: "{{ inventory_hostname }}" 291 | username: "{{ username }}" 292 | password: "{{ password }}" 293 | monitor_name: "monitor02" 294 | state: "absent" 295 | 296 | - name: DELETE MONITOR AGAIN - NO CHANGE 297 | netscaler_lbmonitor: 298 | host: "{{ inventory_hostname }}" 299 | username: "{{ username }}" 300 | password: "{{ password }}" 301 | monitor_name: "monitor02" 302 | state: "absent" 303 | 304 | 305 | 306 | - name: UNITTEST CLEANUP 307 | hosts: netscaler 308 | connection: local 309 | gather_facts: False 310 | tags: cleanup 311 | 312 | tasks: 313 | - name: CLEANUP MONITORS - CHANGE 314 | netscaler_lbmonitor: 315 | host: "{{ inventory_hostname }}" 316 | username: "{{ username }}" 317 | password: "{{ password }}" 318 | state: "absent" 319 | monitor_name: "{{ item }}" 320 | with_items: 321 | - monitor01 322 | - monitor02 323 | - monitor03 324 | - monitor04 325 | - monitor05 326 | - monitor06 327 | 328 | - name: CLEANUP MONITORS IN PARTITION - CHANGE 329 | netscaler_lbmonitor: 330 | host: "{{ inventory_hostname }}" 331 | username: "{{ username }}" 332 | password: "{{ password }}" 333 | state: "absent" 334 | monitor_name: "monitor01" 335 | partition: "LAB" -------------------------------------------------------------------------------- /examples/netscaler_examples.md: -------------------------------------------------------------------------------- 1 | # Shell Output from Running Example Playbooks 2 | This demonstrates how to execute the example playbooks using the example [vars](./vars/examples/) files for playbook variables. The example playbooks are related to each other and should be used in the order presented here. 3 | 4 | ### Deploy New Virtual Server 5 | ``` bash 6 | $ ansible-playbook netscaler_deploy_full.yml --extra-vars "@./vars/example/deploy_full.yml" 7 | 8 | PLAY [PLAY 1 - ENSURE ALL LOAD BALANCER OBJECTS EXIST] ****************************************************** 9 | 10 | TASK [TASK 1 - ENSURE SERVER OBJECTS ARE DEPLOYED] ********************************************************** 11 | changed: [netscaler1] => (item={u'comment': u'Intranet Server', u'ip_address': u'10.10.10.21', u'name': u'prod_rhel_01'}) 12 | changed: [netscaler1] => (item={u'comment': u'Intranet Server', u'ip_address': u'10.10.10.22', u'name': u'prod_rhel_02'}) 13 | changed: [netscaler1] => (item={u'comment': u'Backup Intranet Server', u'ip_address': u'10.10.20.21', u'name': u'dr_rhel_01'}) 14 | changed: [netscaler1] => (item={u'comment': u'Backup Intranet Server', u'ip_address': u'10.10.20.22', u'name': u'dr_rhel_02'}) 15 | 16 | TASK [TASK 2 - ENSURE SERVICE GROUPS ARE DEPLOYED] ********************************************************** 17 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Intranet HTTPS Service Group', u'name': u'svcgrp_intranet_https'}) 18 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Backup Intranet HTTPS Service Group', u'name': u'svcgrp_backup_intranet_https'}) 19 | 20 | TASK [TASK 3 - ENSURE BACKUP LB VSERVERS ARE DEPLOYED] ****************************************************** 21 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Backup Intranet HTTPS VIP', u'state': u'disabled', u'name': u'lbvs_backup_intranet_https', u'persistence': u'SRCIPDESTIP'}) 22 | 23 | TASK [TASK 4 - ENSURE LB VSERVERS ARE DEPLOYED] ************************************************************* 24 | changed: [netscaler1] => (item={u'comment': u'Intranet HTTPS VIP', u'lb_method': u'LEASTCONNECTION', u'name': u'lbvs_intranet_https', u'backup_vserver': u'lbvs_backup_intranet_https', u'service_type': u'SSL_BRIDGE', u'conn_failover': u'STATEFUL', u'ip_address': u'10.10.11.21', u'port': 443, u'persistence': u'SRCIPDESTIP'}) 25 | 26 | TASK [TASK 5 - ENSURE MONITORS ARE DEPLOYED] **************************************************************** 27 | changed: [netscaler1] => (item={u'type': u'HTTP', u'response_code': u'200-202', u'request': u'HEAD /healthcheck.html', u'name': u'lbmon_intranet_https', u'secure': u'YES'}) 28 | changed: [netscaler1] => (item={u'type': u'HTTP', u'response_code': u'200-202', u'request': u'HEAD /healthcheck.html', u'name': u'lbmon_backup_intranet_https', u'secure': u'YES'}) 29 | 30 | PLAY [PLAY 2 - ENSURE ALL BINDINGS EXIST] ******************************************************************* 31 | 32 | TASK [TASK 1 - ENSURE VSEVERS ARE BOUND TO SERVICEGROUPS] *************************************************** 33 | changed: [netscaler1] => (item={u'vserver_name': u'lbvs_intranet_https', u'servicegroup_name': u'svcgrp_intranet_https'}) 34 | changed: [netscaler1] => (item={u'vserver_name': u'lbvs_backup_intranet_https', u'servicegroup_name': u'svcgrp_backup_intranet_https'}) 35 | 36 | TASK [TASK 2 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS] *************************************************** 37 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_https', u'server_name': u'prod_rhel_01', u'port': 443}) 38 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_https', u'server_name': u'prod_rhel_02', u'port': 443}) 39 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_backup_intranet_https', u'server_name': u'dr_rhel_01', u'port': 443}) 40 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_backup_intranet_https', u'server_name': u'dr_rhel_02', u'port': 443}) 41 | 42 | TASK [TASK 3 - ENSURE SERVICEGROUPS ARE BOUND TO MONITORS] ************************************************** 43 | changed: [netscaler1] => (item={u'monitor_name': u'lbmon_intranet_https', u'servicegroup_name': u'svcgrp_intranet_https'}) 44 | changed: [netscaler1] => (item={u'monitor_name': u'lbmon_backup_intranet_https', u'servicegroup_name': u'svcgrp_backup_intranet_https'}) 45 | 46 | PLAY RECAP ************************************************************************************************** 47 | netscaler1 : ok=8 changed=8 unreachable=0 failed=0 48 | $ 49 | ``` 50 | 51 | ### Add Service to Virtual Server 52 | ``` bash 53 | $ ansible-playbook netscaler_deploy_vip.yml --extra-vars "@./vars/example/deploy_vip.yml" 54 | 55 | PLAY [PLAY 1 - ENSURE ALL LOAD BALANCER OBJECTS EXIST] ****************************************************** 56 | 57 | TASK [TASK 1 - ENSURE SERVICE GROUPS ARE DEPLOYED] ********************************************************** 58 | changed: [netscaler1] => (item={u'service_type': u'HTTP', u'comment': u'Intranet HTTP Service Group', u'name': u'svcgrp_intranet_http'}) 59 | 60 | TASK [TASK 2 - ENSURE LB VSERVERS ARE DEPLOYED] ************************************************************* 61 | changed: [netscaler1] => (item={u'comment': u'Intranet HTTP VIP', u'lb_method': u'LEASTCONNECTION', u'name': u'lbvs_intranet_http', u'service_type': u'HTTP', u'ip_address': u'10.10.11.21', u'port': 80, u'persistence': u'SRCIPDESTIP'}) 62 | 63 | TASK [TASK 3 - ENSURE MONITORS ARE DEPLOYED] **************************************************************** 64 | changed: [netscaler1] => (item={u'type': u'HTTP', u'response_code': u'200', u'request': u'HEAD /healthcheck.html', u'name': u'lbmon_intranet_http', u'secure': u'YES'}) 65 | 66 | PLAY [PLAY 2 - ENSURE ALL BINDINGS EXIST] ******************************************************************* 67 | 68 | TASK [TASK 1 - ENSURE VSEVERS ARE BOUND TO SERVICEGROUPS] *************************************************** 69 | changed: [netscaler1] => (item={u'vserver_name': u'lbvs_intranet_http', u'servicegroup_name': u'svcgrp_intranet_http'}) 70 | 71 | TASK [TASK 2 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS] *************************************************** 72 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_http', u'server_name': u'prod_rhel_01', u'port': 80}) 73 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_http', u'server_name': u'prod_rhel_02', u'port': 80}) 74 | 75 | TASK [TASK 3 - ENSURE SERVICEGROUPS ARE BOUND TO MONITORS] ************************************************** 76 | changed: [netscaler1] => (item={u'monitor_name': u'lbmon_intranet_http', u'servicegroup_name': u'svcgrp_intranet_http'}) 77 | 78 | PLAY RECAP ************************************************************************************************** 79 | netscaler1 : ok=6 changed=6 unreachable=0 failed=0 80 | ``` 81 | 82 | ### Disable Server 83 | ``` bash 84 | $ ansible-playbook netscaler_change_server_state.yml --extra-vars "server_name=prod_rhel_01" 85 | 86 | PLAY [PLAY 1 - MANAGE SERVER STATE] ************************************************************************* 87 | 88 | TASK [TASK 1 - ENSURE SERVER IS IN DESIRED STATE] *********************************************************** 89 | changed: [netscaler1] 90 | 91 | PLAY RECAP ************************************************************************************************** 92 | netscaler1 : ok=1 changed=1 unreachable=0 failed=0 93 | ``` 94 | 95 | ### Add Server to Virtual Servers 96 | ``` bash 97 | $ ansible-playbook netscaler_add_server.yml --extra-vars "@./vars/example/add_server.yml" 98 | 99 | PLAY [PLAY 1 - ENSURE ALL SERVER OBJECTS EXIST] ************************************************************* 100 | 101 | TASK [TASK 1 - ENSURE SERVER OBJECTS ARE DEPLOYED] ********************************************************** 102 | changed: [netscaler1] => (item={u'comment': u'Intranet Server', u'ip_address': u'10.10.10.23', u'name': u'prod_rhel_03'}) 103 | changed: [netscaler1] => (item={u'comment': u'Backup Intranet Server', u'ip_address': u'10.10.20.23', u'name': u'dr_rhel_03'}) 104 | 105 | PLAY [PLAY 2 - ENSURE ALL BINDINGS EXIST] ******************************************************************* 106 | 107 | TASK [TASK 1 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS] *************************************************** 108 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_https', u'server_name': u'prod_rhel_03', u'port': 443}) 109 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_backup_intranet_https', u'server_name': u'dr_rhel_03', u'port': 443}) 110 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_intranet_http', u'server_name': u'prod_rhel_03', u'port': 80}) 111 | 112 | PLAY RECAP ************************************************************************************************** 113 | netscaler1 : ok=2 changed=2 unreachable=0 failed=0 114 | ``` 115 | 116 | ### Enable Server 117 | ```bash 118 | $ ansible-playbook netscaler_change_server_state.yml --extra-vars "server_name=prod_rhel_01 server_state=enabled" 119 | 120 | PLAY [PLAY 1 - MANAGE SERVER STATE] ************************************************************************* 121 | 122 | TASK [TASK 1 - ENSURE SERVER IS IN DESIRED STATE] *********************************************************** 123 | changed: [netscaler1] 124 | 125 | PLAY RECAP ************************************************************************************************** 126 | netscaler1 : ok=1 changed=1 unreachable=0 failed=0 127 | ``` 128 | 129 | ### Deploy Virtual Server to Partition 130 | ``` bash 131 | $ ansible-playbook netscaler_deploy_full.yml --extra-vars "@./vars/example/full_partition.yml" 132 | 133 | PLAY [PLAY 1 - ENSURE ALL LOAD BALANCER OBJECTS EXIST] ****************************************************** 134 | 135 | TASK [TASK 1 - ENSURE SERVER OBJECTS ARE DEPLOYED] ********************************************************** 136 | changed: [netscaler1] => (item={u'comment': u'Dev Intranet Server', u'ip_address': u'10.10.12.21', u'name': u'prod_rhel_04'}) 137 | changed: [netscaler1] => (item={u'comment': u'Dev Backup Intranet Server', u'ip_address': u'10.10.22.21', u'name': u'dr_rhel_04'}) 138 | 139 | TASK [TASK 2 - ENSURE SERVICE GROUPS ARE DEPLOYED] ********************************************************** 140 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Dev Intranet Service Group', u'name': u'svcgrp_dev_intranet_https'}) 141 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Dev Backup Intranet HTTPS Service Group', u'name': u'svcgrp_dev_backup_intranet_https'}) 142 | 143 | TASK [TASK 3 - ENSURE BACKUP LB VSERVERS ARE DEPLOYED] ****************************************************** 144 | changed: [netscaler1] => (item={u'service_type': u'SSL_BRIDGE', u'comment': u'Dev Backup Intranet HTTPS VIP', u'state': u'disabled', u'name': u'lbvs_dev_backup_intranet_https', u'persistence': u'SRCIPDESTIP'}) 145 | 146 | TASK [TASK 4 - ENSURE LB VSERVERS ARE DEPLOYED] ************************************************************* 147 | changed: [netscaler1] => (item={u'comment': u'Dev Intranet HTTPS VIP', u'lb_method': u'LEASTCONNECTION', u'name': u'lbvs_dev_intranet_https', u'backup_vserver': u'lbvs_dev_backup_intranet_https', u'service_type': u'SSL_BRIDGE', u'ip_address': u'10.10.13.21', u'port': 443, u'persistence': u'SRCIPDESTIP'}) 148 | 149 | TASK [TASK 5 - ENSURE MONITORS ARE DEPLOYED] **************************************************************** 150 | changed: [netscaler1] => (item={u'type': u'HTTP', u'response_code': u'200-202', u'request': u'HEAD /healthcheck.html', u'name': u'lbmon_dev_intranet_https', u'secure': u'YES'}) 151 | changed: [netscaler1] => (item={u'type': u'HTTP', u'response_code': u'200-202', u'request': u'HEAD /healthcheck.html', u'name': u'lbmon_dev_backup_intranet_https', u'secure': u'YES'}) 152 | 153 | PLAY [PLAY 2 - ENSURE ALL BINDINGS EXIST] ******************************************************************* 154 | 155 | TASK [TASK 1 - ENSURE VSEVERS ARE BOUND TO SERVICEGROUPS] *************************************************** 156 | changed: [netscaler1] => (item={u'vserver_name': u'lbvs_dev_intranet_https', u'servicegroup_name': u'svcgrp_dev_intranet_https'}) 157 | changed: [netscaler1] => (item={u'vserver_name': u'lbvs_dev_backup_intranet_https', u'servicegroup_name': u'svcgrp_dev_backup_intranet_https'}) 158 | 159 | TASK [TASK 2 - ENSURE SERVICEGROUPS ARE BOUND TO SERVERS] *************************************************** 160 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_dev_intranet_https', u'server_name': u'prod_rhel_04', u'port': 443}) 161 | changed: [netscaler1] => (item={u'servicegroup_name': u'svcgrp_dev_backup_intranet_https', u'server_name': u'dr_rhel_04', u'port': 443}) 162 | 163 | TASK [TASK 3 - ENSURE SERVICEGROUPS ARE BOUND TO MONITORS] ************************************************** 164 | changed: [netscaler1] => (item={u'monitor_name': u'lbmon_dev_intranet_https', u'servicegroup_name': u'svcgrp_dev_intranet_https'}) 165 | changed: [netscaler1] => (item={u'monitor_name': u'lbmon_dev_backup_intranet_https', u'servicegroup_name': u'svcgrp_dev_backup_intranet_https'}) 166 | 167 | PLAY RECAP ************************************************************************************************** 168 | netscaler1 : ok=8 changed=8 unreachable=0 failed=0 169 | ``` -------------------------------------------------------------------------------- /unittests/netscaler_lbvserver_unittest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: UNITTEST 3 | hosts: netscaler 4 | connection: local 5 | gather_facts: False 6 | 7 | tasks: 8 | - name: CONFIG LB VSERVER - CHANGE 9 | netscaler_lbvserver: 10 | host: "{{ inventory_hostname }}" 11 | username: "{{ username }}" 12 | password: "{{ password }}" 13 | lbvserver_name: "lbvserver01" 14 | ip_address: "10.10.20.21" 15 | service_type: "http" 16 | comment: "Comments Work" 17 | lbmethod: "roundrobin" 18 | lbvserver_port: 80 19 | persistence: "srcipdestip" 20 | 21 | - name: CONFIG LB VSERVER AGAIN - NO CHANGE 22 | netscaler_lbvserver: 23 | host: "{{ inventory_hostname }}" 24 | username: "{{ username }}" 25 | password: "{{ password }}" 26 | lbvserver_name: "lbvserver01" 27 | ip_address: "10.10.20.21" 28 | service_type: "http" 29 | comment: "Comments Work" 30 | lbmethod: "ROUNDROBIN" 31 | lbvserver_port: 80 32 | persistence: "SRCIPDESTIP" 33 | 34 | - name: CONFIG LB VSERVER AGAIN LESS PARAMS - NO CHANGE 35 | netscaler_lbvserver: 36 | host: "{{ inventory_hostname }}" 37 | username: "{{ username }}" 38 | password: "{{ password }}" 39 | lbvserver_name: "lbvserver01" 40 | ip_address: "10.10.20.21" 41 | service_type: "HTTP" 42 | 43 | - name: CONFIG LB VSERVER SAME IP DIFFERENT PORT AND SERVICE - CHANGE 44 | netscaler_lbvserver: 45 | host: "{{ inventory_hostname }}" 46 | username: "{{ username }}" 47 | password: "{{ password }}" 48 | lbvserver_name: "lbvserver20" 49 | ip_address: "10.10.20.21" 50 | service_type: "SSL" 51 | comment: "Comments Work" 52 | lbmethod: "ROUNDROBIN" 53 | lbvserver_port: 443 54 | persistence: "SRCIPDESTIP" 55 | 56 | - name: CONFIG LB VSERVER IN PARTITION - CHANGE 57 | netscaler_lbvserver: 58 | host: "{{ inventory_hostname }}" 59 | username: "{{ username }}" 60 | password: "{{ password }}" 61 | lbvserver_name: "lbvserver01" 62 | ip_address: "10.10.30.21" 63 | service_type: "ssl_bridge" 64 | lbvserver_port: 443 65 | partition: "LAB" 66 | 67 | - name: UPDATE LB VSERVER AND DISABLE- CHANGE 68 | netscaler_lbvserver: 69 | host: "{{ inventory_hostname }}" 70 | username: "{{ username }}" 71 | password: "{{ password }}" 72 | lbvserver_name: "lbvserver01" 73 | comment: "Comments Still Work" 74 | client_timeout: 300 75 | lbmethod: "roundrobin" 76 | lbvserver_state: "disabled" 77 | persistence: "srcipdestip" 78 | partition: "LAB" 79 | 80 | - name: CONFIG LB VSERVER IN TRAFFIC DOMAIN - CHANGE 81 | netscaler_lbvserver: 82 | host: "{{ inventory_hostname }}" 83 | username: "{{ username }}" 84 | password: "{{ password }}" 85 | lbvserver_name: "lbvserver02" 86 | ip_address: "10.10.20.22" 87 | lbvserver_port: 22 88 | service_type: "TCP" 89 | traffic_domain: 10 90 | 91 | - name: CONFIG LB VSERVER IN TRAFFIC DOMAIN WITH DUPLICATE IP FROM DEFAULT TRAFFIC DOMAIN - CHANGE 92 | netscaler_lbvserver: 93 | host: "{{ inventory_hostname }}" 94 | username: "{{ username }}" 95 | password: "{{ password }}" 96 | lbvserver_name: "lbvserver100" 97 | ip_address: "10.10.20.21" 98 | lbvserver_port: 80 99 | service_type: "HTTP" 100 | traffic_domain: 10 101 | 102 | - name: CONFIG BACKUP LB VSERVER - CHANGE 103 | netscaler_lbvserver: 104 | host: "{{ inventory_hostname }}" 105 | username: "{{ username }}" 106 | password: "{{ password }}" 107 | lbvserver_name: "lbvserver03" 108 | service_type: "SSL_BRIDGE" 109 | 110 | - name: CONFIG PRIMARY LB VSERVER - CHANGE 111 | netscaler_lbvserver: 112 | host: "{{ inventory_hostname }}" 113 | username: "{{ username }}" 114 | password: "{{ password }}" 115 | lbvserver_name: "lbvserver04" 116 | ip_address: "10.10.20.24" 117 | service_type: "SSL_BRIDGE" 118 | backup_lbvserver: "lbvserver03" 119 | conn_failover: "STATEFUL" 120 | lbmethod: "ROUNDROBIN" 121 | lbvserver_port: 443 122 | persistence: "SRCIPDESTIP" 123 | 124 | - name: DISABLE LB VSERVER - CHANGE 125 | netscaler_lbvserver: 126 | host: "{{ inventory_hostname }}" 127 | username: "{{ username }}" 128 | password: "{{ password }}" 129 | lbvserver_name: "lbvserver04" 130 | lbvserver_state: "disabled" 131 | 132 | - name: ENABLE LB VSERVER AND CHANGE FAILOVER TYPE - CHANGE 133 | netscaler_lbvserver: 134 | host: "{{ inventory_hostname }}" 135 | username: "{{ username }}" 136 | password: "{{ password }}" 137 | lbvserver_name: "lbvserver04" 138 | lbvserver_state: "enabled" 139 | conn_failover: "STATEFUL" 140 | 141 | - name: CONFIG LB VSERVER ANY SERVICE - CHANGE 142 | netscaler_lbvserver: 143 | host: "{{ inventory_hostname }}" 144 | username: "{{ username }}" 145 | password: "{{ password }}" 146 | lbvserver_name: "lbvserver05" 147 | ip_address: "10.10.20.25" 148 | service_type: "ANY" 149 | conn_failover: "STATEFUL" 150 | lbmethod: "ROUNDROBIN" 151 | lbvserver_port: "*" 152 | persistence: "SRCIPDESTIP" 153 | app_flow_log: "disabled" 154 | 155 | - name: CONFIG LB VSERVER ANY SERVICE AGAIN - NO CHANGE 156 | netscaler_lbvserver: 157 | host: "{{ inventory_hostname }}" 158 | username: "{{ username }}" 159 | password: "{{ password }}" 160 | lbvserver_name: "lbvserver05" 161 | ip_address: "10.10.20.25" 162 | service_type: "ANY" 163 | conn_failover: "STATEFUL" 164 | lbmethod: "ROUNDROBIN" 165 | lbvserver_port: "*" 166 | persistence: "SRCIPDESTIP" 167 | app_flow_log: "disabled" 168 | 169 | - name: DELETE LB VSERVER - CHANGE 170 | netscaler_lbvserver: 171 | host: "{{ inventory_hostname }}" 172 | username: "{{ username }}" 173 | password: "{{ password }}" 174 | lbvserver_name: "lbvserver02" 175 | state: absent 176 | 177 | - name: DELETE LB VSERVER AGAIN - NO CHANGE 178 | netscaler_lbvserver: 179 | host: "{{ inventory_hostname }}" 180 | username: "{{ username }}" 181 | password: "{{ password }}" 182 | lbvserver_name: "lbvserver02" 183 | state: absent 184 | 185 | - name: SET PROVIDER - NO CHANGE 186 | set_fact: 187 | provider: 188 | host: "{{ inventory_hostname }}" 189 | username: "{{ username }}" 190 | password: "{{ password }}" 191 | lbvserver_name: "lbvserver05" 192 | ip_address: "10.10.20.25" 193 | service_type: "ANY" 194 | conn_failover: "STATEFUL" 195 | lbmethod: "ROUNDROBIN" 196 | lbvserver_port: "*" 197 | persistence: "SRCIPDESTIP" 198 | 199 | - name: CONFIG LB VSERVER WITH PROVIDER - NO CHANGE 200 | netscaler_lbvserver: 201 | provider: "{{ provider }}" 202 | 203 | - name: CONFIG LB VSERVER OVERRIDE PROVIDER - NO CHANGE 204 | netscaler_lbvserver: 205 | host: "{{ inventory_hostname }}" 206 | username: "{{ username }}" 207 | password: "{{ password }}" 208 | lbvserver_name: "lbvserver06" 209 | ip_address: "10.10.20.26" 210 | service_type: "http" 211 | conn_failover: "disabled" 212 | lbmethod: "leastconnection" 213 | lbvserver_port: 80 214 | persistence: "sourceip" 215 | 216 | - name: CONFIG LB VSERVER NO HOST - FAIL 217 | netscaler_lbvserver: 218 | username: "{{ username }}" 219 | password: "{{ password }}" 220 | lbvserver_name: "lbvserver01" 221 | ip_address: "10.10.20.100" 222 | service_type: "HTTP" 223 | ignore_errors: yes 224 | tags: no_name 225 | 226 | - name: CONFIG LB VSERVER NO NAME - FAIL 227 | netscaler_lbvserver: 228 | host: "{{ inventory_hostname }}" 229 | username: "{{ username }}" 230 | password: "{{ password }}" 231 | ip_address: "10.10.20.100" 232 | service_type: "HTTP" 233 | ignore_errors: yes 234 | tags: no_name 235 | 236 | - name: CONFIG LB VSERVER NO IP ADDRESS WITH PORT - FAIL 237 | netscaler_lbvserver: 238 | host: "{{ inventory_hostname }}" 239 | username: "{{ username }}" 240 | password: "{{ password }}" 241 | lbvserver_name: "lbvserver10" 242 | lbvserver_port: 8080 243 | service_type: "HTTP" 244 | ignore_errors: yes 245 | tags: no_ip 246 | 247 | - name: CONFIG LB VSERVER NO SERVICE TYPE - FAIL 248 | netscaler_lbvserver: 249 | host: "{{ inventory_hostname }}" 250 | username: "{{ username }}" 251 | password: "{{ password }}" 252 | lbvserver_name: "lbvserver10" 253 | lbvserver_port: 443 254 | ip_address: "10.10.20.100" 255 | ignore_errors: yes 256 | tags: no_type 257 | 258 | - name: CONFIG LB VSERVER DUPLICATE NAME - FAIL 259 | netscaler_lbvserver: 260 | host: "{{ inventory_hostname }}" 261 | username: "{{ username }}" 262 | password: "{{ password }}" 263 | lbvserver_name: "lbvserver01" 264 | ip_address: "10.10.20.100" 265 | service_type: "HTTP" 266 | ignore_errors: yes 267 | tags: dup_name 268 | 269 | - name: CONFIG LB VSERVER DUPLICATE IP AND PORT - FAIL 270 | netscaler_lbvserver: 271 | host: "{{ inventory_hostname }}" 272 | username: "{{ username }}" 273 | password: "{{ password }}" 274 | lbvserver_name: "lbvserver10" 275 | lbvserver_port: 80 276 | ip_address: "10.10.20.21" 277 | service_type: "TCP" 278 | ignore_errors: yes 279 | tags: dup_ip 280 | 281 | - name: CONFIG LB VSERVER DUPLICATE NAME OVERRIDE (RE-IP EXISTING LB VSERVER) - CHANGE 282 | netscaler_lbvserver: 283 | host: "{{ inventory_hostname }}" 284 | username: "{{ username }}" 285 | password: "{{ password }}" 286 | lbvserver_name: "lbvserver01" 287 | ip_address: "10.10.20.100" 288 | service_type: "HTTP" 289 | config_override: true 290 | ignore_errors: yes 291 | tags: dup_name 292 | 293 | - name: CONFIG LB VSERVER DUPLICATE IP AND PORT OVERRIDE (RE-NAME EXISTING LB VSERVER) - CHANGE 294 | netscaler_lbvserver: 295 | host: "{{ inventory_hostname }}" 296 | username: "{{ username }}" 297 | password: "{{ password }}" 298 | lbvserver_name: "lbvserver15" 299 | lbvserver_port: 80 300 | ip_address: "10.10.20.100" 301 | service_type: "HTTP" 302 | config_override: true 303 | ignore_errors: yes 304 | tags: dup_ip 305 | 306 | - name: CONFIG LB VSERVER INVALID TRAFFIC DOMAIN - FAIL 307 | netscaler_lbvserver: 308 | host: "{{ inventory_hostname }}" 309 | username: "{{ username }}" 310 | password: "{{ password }}" 311 | lbvserver_name: "lbvserver10" 312 | ip_address: "10.10.20.100" 313 | lbvserver_port: 22 314 | service_type: "TCP" 315 | traffic_domain: 20 316 | ignore_errors: yes 317 | tags: bad_td 318 | 319 | - name: CONFIG LB VSERVER BAD SERVICE TYPE - FAIL 320 | netscaler_lbvserver: 321 | host: "{{ inventory_hostname }}" 322 | username: "{{ username }}" 323 | password: "{{ password }}" 324 | lbvserver_name: "lbvserver10" 325 | ip_address: "10.10.20.100" 326 | service_type: "FAKE" 327 | ignore_errors: yes 328 | tags: bad_type 329 | 330 | - name: CONFIG LB VSERVER BAD LB METHOD - FAIL 331 | netscaler_lbvserver: 332 | host: "{{ inventory_hostname }}" 333 | username: "{{ username }}" 334 | password: "{{ password }}" 335 | lbvserver_name: "lbvserver10" 336 | ip_address: "10.10.20.100" 337 | service_type: "TCP" 338 | lbmethod: "FAKE" 339 | ignore_errors: yes 340 | tags: bad_method 341 | 342 | - name: CONFIG LB VSERVER BAD PERSISTENCE TYPE - FAIL 343 | netscaler_lbvserver: 344 | host: "{{ inventory_hostname }}" 345 | username: "{{ username }}" 346 | password: "{{ password }}" 347 | lbvserver_name: "lbvserver10" 348 | ip_address: "10.10.20.100" 349 | service_type: "HTTP" 350 | lbmethod: "ROUNDROBIN" 351 | persistence: "FAKE" 352 | ignore_errors: yes 353 | tags: bad_persist 354 | 355 | - name: CONFIG LB VSERVER PORT * ANY PORT NOT * - FAIL 356 | netscaler_lbvserver: 357 | host: "{{ inventory_hostname }}" 358 | username: "{{ username }}" 359 | password: "{{ password }}" 360 | lbvserver_name: "lbvserver10" 361 | lbvserver_port: "*" 362 | ip_address: "10.10.20.100" 363 | service_type: "TCP" 364 | lbmethod: "ROUNDROBIN" 365 | ignore_errors: yes 366 | tags: bad_type 367 | 368 | - name: CONFIG LB VSERVER IP 0.0.0.0 PORT NOT 0 - FAIL 369 | netscaler_lbvserver: 370 | host: "{{ inventory_hostname }}" 371 | username: "{{ username }}" 372 | password: "{{ password }}" 373 | lbvserver_name: "lbvserver10" 374 | lbvserver_port: "22" 375 | ip_address: "0.0.0.0" 376 | service_type: "ANY" 377 | lbmethod: "ROUNDROBIN" 378 | ignore_errors: yes 379 | tags: bad_port 380 | 381 | - name: CONFIG LB VSERVER USEABLE IP PORT 0 - FAIL 382 | netscaler_lbvserver: 383 | host: "{{ inventory_hostname }}" 384 | username: "{{ username }}" 385 | password: "{{ password }}" 386 | lbvserver_name: "lbvserver10" 387 | lbvserver_port: "0" 388 | ip_address: "10.10.20.100" 389 | service_type: "TCP" 390 | lbmethod: "ROUNDROBIN" 391 | ignore_errors: yes 392 | tags: bad_port 393 | 394 | - name: CHANGE LB VSERVER SERVICE TYPE - FAIL 395 | netscaler_lbvserver: 396 | host: "{{ inventory_hostname }}" 397 | username: "{{ username }}" 398 | password: "{{ password }}" 399 | lbvserver_name: "lbvserver15" 400 | ip_address: "10.10.20.100" 401 | service_type: "SSL_BRIDGE" 402 | lbmethod: "ROUNDROBIN" 403 | lbvserver_port: 80 404 | persistence: "SRCIPDESTIP" 405 | ignore_errors: yes 406 | tags: change_type 407 | 408 | - name: CHANGE LB VSERVER TRAFFIC DOMAIN - FAIL 409 | netscaler_lbvserver: 410 | host: "{{ inventory_hostname }}" 411 | username: "{{ username }}" 412 | password: "{{ password }}" 413 | lbvserver_name: "lbvserver15" 414 | ip_address: "10.10.20.100" 415 | service_type: "HTTP" 416 | lbvserver_port: 80 417 | traffic_domain: 10 418 | ignore_errors: yes 419 | tags: change_td 420 | 421 | - name: CHANGE LB VSERVER PORT - FAIL 422 | netscaler_lbvserver: 423 | host: "{{ inventory_hostname }}" 424 | username: "{{ username }}" 425 | password: "{{ password }}" 426 | lbvserver_name: "lbvserver15" 427 | ip_address: "10.10.20.100" 428 | service_type: "HTTP" 429 | lbvserver_port: 443 430 | ignore_errors: yes 431 | tags: change_port 432 | 433 | 434 | 435 | - name: UNITTEST CLEANUP 436 | hosts: netscaler 437 | connection: local 438 | gather_facts: False 439 | tags: cleanup 440 | 441 | tasks: 442 | - name: CLEANUP LB VSERVERS - CHANGE 443 | netscaler_lbvserver: 444 | host: "{{ inventory_hostname }}" 445 | username: "{{ username }}" 446 | password: "{{ password }}" 447 | state: "absent" 448 | lbvserver_name: "{{ item }}" 449 | with_items: 450 | - "lbvserver01" 451 | - "lbvserver02" 452 | - "lbvserver03" 453 | - "lbvserver04" 454 | - "lbvserver05" 455 | - "lbvserver06" 456 | - "lbvserver10" 457 | - "lbvserver15" 458 | - "lbvserver20" 459 | - "lbvserver100" 460 | 461 | - name: CLEANUP LB VSERVERS IN PARTITION - CHANGE 462 | netscaler_lbvserver: 463 | host: "{{ inventory_hostname }}" 464 | username: "{{ username }}" 465 | password: "{{ password }}" 466 | state: "absent" 467 | lbvserver_name: "lbvserver01" 468 | partition: "LAB" -------------------------------------------------------------------------------- /Module_Docs/netscaler_module_docs.md: -------------------------------------------------------------------------------- 1 | # Citrix Netscaler Modules 2 | 3 | --- 4 | ### Requirements 5 | * Python `requests` 6 | * Everything tested was with Netscaler version 11.x 7 | 8 | --- 9 | ### Modules 10 | 11 | * [netscaler_lbvserver - manages lb vserver resources and attributes.](#netscaler_lbvserver) 12 | * [netscaler_monitor - manages monitor resources and attributes](#netscaler_monitor) 13 | * [netscaler_lbvserver_certkey - manages lbvserver to cert key bindings](#netscaler_lbvserver_certkey) 14 | * [netscaler_servicegroup_server - manages service group to server bindings.](#netscaler_servicegroup_server) 15 | * [netscaler_lbvserver_servicegroup - manages lbvserver to service group bindings.](#netscaler_lbvserver_servicegroup) 16 | * [netscaler_servicegroup_monitor - manages service group to monitor bindings.](#netscaler_servicegroup_monitor) 17 | * [netscaler_facts - gathers netscaler facts](#netscaler_facts) 18 | * [netscaler_server - manages server resources and attributes](#netscaler_server) 19 | * [netscaler_save_config - saves the running configuration to the netscaler.](#netscaler_save_config) 20 | * [netscaler_servicegroup - manages service group resources and attributes](#netscaler_servicegroup) 21 | 22 | --- 23 | 24 | ## netscaler_lbvserver 25 | Manages LB VServer resources and attributes. 26 | 27 | * Synopsis 28 | * Options 29 | * Examples 30 | 31 | #### Synopsis 32 | Manages Netscaler LB VServer configurations using Nitro API. 33 | 34 | #### Options 35 | 36 | | Parameter | required | default | choices | comments | 37 | | ------------- |-------------| ---------|----------- |--------- | 38 | | comment | no | | | A comment about the lbvserver | 39 | | lbvserver_port | no | | | The port the lbvserver will listen on. Valid protocol port ranges and "*" are supported. | 40 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 41 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 42 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 43 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 44 | | service_type | no | | | The type of service the lbvserver provides. | 45 | | conn_failover | no | | | The lbvserver connection setting | 46 | | lbmethod | no | | | The method to load balance traffic. | 47 | | persistence | no | | | The persistence type used by the lbvserver. | 48 | | client_timeout | no | | | Seconds to wait before terminating a client session. Valid inputs are from 0 to 31536000. | 49 | | username | yes | | | The username used to authenticate with the Netscaler. | 50 | | cookie_name | no | | | The name of the cookie to use. Used with a COOKIE persistence type. | 51 | | lbvserver_state | no | enabled | | The resources desired activity. Disabled marks it out of service. Enabled marks it serviceable. | 52 | | host | yes | | | The Netscaler's Address. | 53 | | password | no | | | The password associated with the username account. | 54 | | ip_address | no | | | The IP address of the Server Object. | 55 | | backup_lbvserver | no | | | The name of the backup lbvserver | 56 | | traffic_domain | no | 0 | | The traffic domain associated with the servicegroup | 57 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 58 | | lbvserver_name | yes | | | The name of the lbvserver object | 59 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 60 | 61 | 62 | 63 | 64 | 65 | --- 66 | 67 | 68 | ## netscaler_monitor 69 | Manages Monitor resources and attributes 70 | 71 | * Synopsis 72 | * Options 73 | * Examples 74 | 75 | #### Synopsis 76 | Manages Netscaler Monitor configurations using Nitro API 77 | 78 | #### Options 79 | 80 | | Parameter | required | default | choices | comments | 81 | | ------------- |-------------| ---------|----------- |--------- | 82 | | monitor_secondary_password | no | | | A secondary password to authenticate with the monitored service | 83 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 84 | | monitor_name | yes | | | The name of the monitor | 85 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 86 | | response_code_action | no | add | | The action to take for response code items that differ from existing response codes. add will add any missing values to the existing response codes. remove will remove any matching values to the existing response codes. | 87 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 88 | | monitor_use_ssl | no | | | Specifies to use SSL for the monitor | 89 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 90 | | username | yes | | | The username used to authenticate with the Netscaler. | 91 | | http_request | no | | | The request to send to the server | 92 | | monitor_dest_ip | no | | | The IP address to monitor. | 93 | | monitor_dest_port | no | | | The port to monitor on the server | 94 | | monitor_state | no | enabled | | The resources desired activity. Disabled marks it out of service. Enabled marks it serviceable. | 95 | | monitor_password | no | | | The password used to authenticate with the monitored service. | 96 | | host | yes | | | The Netscaler's Address. | 97 | | custom_headers | no | | | Custom headers to add to the monitor request | 98 | | password | no | | | The password associated with the username account. | 99 | | response_code | no | | | The HTTP response code expected back from the monitored resource. | 100 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 101 | | monitor_username | no | | | The username used to authenticate with the monitored service. | 102 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 103 | | monitor_type | no | | | The type of service to monitor | 104 | 105 | 106 | 107 | 108 | 109 | --- 110 | 111 | 112 | ## netscaler_lbvserver_certkey 113 | Manages lbvserver to cert key bindings 114 | 115 | * Synopsis 116 | * Options 117 | * Examples 118 | 119 | #### Synopsis 120 | Manages Netscaler lbvserver to cert key binding configurations using Nitro API 121 | 122 | #### Options 123 | 124 | | Parameter | required | default | choices | comments | 125 | | ------------- |-------------| ---------|----------- |--------- | 126 | | username | yes | | | The username used to authenticate with the Netscaler. | 127 | | vserver_name | yes | | | The name of the vserver to bind the cert key to. | 128 | | ocsp_check | no | | | The state of the OCSP check parameter. | 129 | | skip_ca_name | no | | | Used to indicate whether CA Name needs to be sent to the SSL client during the SSL handshake. | 130 | | ca_cert | no | | | Specifies if the certificate is a CA. | 131 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 132 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 133 | | crl_check | | | | The state of the CRL check parameter. | 134 | | sni_cert | | | | Specifies if SNI processing is in use. | 135 | | host | yes | | | The Netscaler's Address. | 136 | | cert_key_name | yes | | | The name of the cert key to bind to the lbvserver. | 137 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 138 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 139 | | password | no | | | The password associated with the username account. | 140 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 141 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 142 | 143 | 144 | 145 | 146 | 147 | --- 148 | 149 | 150 | ## netscaler_servicegroup_server 151 | Manages service group to server bindings. 152 | 153 | * Synopsis 154 | * Options 155 | * Examples 156 | 157 | #### Synopsis 158 | Manages Netscaler service group to server binding configurations using Nitro API. 159 | 160 | #### Options 161 | 162 | | Parameter | required | default | choices | comments | 163 | | ------------- |-------------| ---------|----------- |--------- | 164 | | username | yes | | | The username used to authenticate with the Netscaler. | 165 | | servicegroup_name | yes | | | The service group name which the server is being bound to. | 166 | | server_name | yes | | | The server name which is being bound to a service group. | 167 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 168 | | host | yes | | | The Netscaler's Address. | 169 | | weight | no | | | The weight to assing the servers in the Service Group. | 170 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 171 | | server_port | yes | | | The port the server is listening on to offer services. | 172 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 173 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 174 | | password | no | | | The password associated with the username account. | 175 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 176 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 177 | 178 | 179 | 180 | 181 | 182 | --- 183 | 184 | 185 | ## netscaler_lbvserver_servicegroup 186 | Manages lbvserver to service group bindings. 187 | 188 | * Synopsis 189 | * Options 190 | * Examples 191 | 192 | #### Synopsis 193 | Manages Netscaler lbvserver to service group binding configurations using Nitro API. 194 | 195 | #### Options 196 | 197 | | Parameter | required | default | choices | comments | 198 | | ------------- |-------------| ---------|----------- |--------- | 199 | | username | yes | | | The username used to authenticate with the Netscaler. | 200 | | servicegroup_name | yes | | | The service group name which the lbvserver is being bound to. | 201 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 202 | | host | yes | | | The Netscaler's Address. | 203 | | lbvserver_name | yes | | | The lbvserver name which is being bound to a service group. | 204 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 205 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 206 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 207 | | password | no | | | The password associated with the username account. | 208 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 209 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 210 | 211 | 212 | 213 | 214 | 215 | --- 216 | 217 | 218 | ## netscaler_servicegroup_monitor 219 | Manages service group to monitor bindings. 220 | 221 | * Synopsis 222 | * Options 223 | * Examples 224 | 225 | #### Synopsis 226 | Manages Netscaler service group to monitor binding configurations using Nitro API. 227 | 228 | #### Options 229 | 230 | | Parameter | required | default | choices | comments | 231 | | ------------- |-------------| ---------|----------- |--------- | 232 | | username | yes | | | The username used to authenticate with the Netscaler. | 233 | | servicegroup_name | yes | | | The service group name which the server is being bound to. | 234 | | weight | no | | | The weight to assing the servers in the Service Group. | 235 | | monitor_name | yes | | | The monitor name which is being bound to a service group. | 236 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 237 | | host | yes | | | The Netscaler's Address. | 238 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 239 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 240 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 241 | | password | no | | | The password associated with the username account. | 242 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 243 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 244 | 245 | 246 | 247 | 248 | 249 | --- 250 | 251 | 252 | ## netscaler_facts 253 | Gathers Netscaler Facts 254 | 255 | * Synopsis 256 | * Options 257 | * Examples 258 | 259 | #### Synopsis 260 | Gathers System, Hardware, and Configuration Facts for Netscaler Nitro API 261 | 262 | #### Options 263 | 264 | | Parameter | required | default | choices | comments | 265 | | ------------- |-------------| ---------|----------- |--------- | 266 | | username | yes | | | The username used to authenticate with the Netscaler. | 267 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 268 | | config_scope | no | false | | The configuration scope to retrieve; used when gathering "config" fact. setting to "true" will include default configuration values. | 269 | | host | yes | | | The Netscaler's Address. | 270 | | gather_subset | no | [u'all'] | | The list of facts to gather. Gathered facts are limited using either an include list, or using an exclude list ("!..."). | 271 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 272 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 273 | | password | no | | | The password associated with the username account. | 274 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 275 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 276 | 277 | 278 | 279 | 280 | 281 | --- 282 | 283 | 284 | ## netscaler_server 285 | Manages Server resources and attributes 286 | 287 | * Synopsis 288 | * Options 289 | * Examples 290 | 291 | #### Synopsis 292 | Manages Netscaler Server configurations using Nitro API 293 | 294 | #### Options 295 | 296 | | Parameter | required | default | choices | comments | 297 | | ------------- |-------------| ---------|----------- |--------- | 298 | | username | yes | | | The username used to authenticate with the Netscaler. | 299 | | comment | no | | | A comment to add to the object. | 300 | | server_name | no | | | The name of the Server Object. | 301 | | server_state | no | enabled | | The server's desired activity. Disabled marks it out of service. Enabled marks it serviceable. | 302 | | traffic_domain | no | 0 | | The traffic domain the server should belong to. | 303 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 304 | | host | yes | | | The Netscaler's Address. | 305 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 306 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 307 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 308 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 309 | | password | no | | | The password associated with the username account. | 310 | | ip_address | no | | | The IP address of the Server Object. | 311 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 312 | 313 | 314 | 315 | 316 | 317 | --- 318 | 319 | 320 | ## netscaler_save_config 321 | Saves the running configuration to the Netscaler. 322 | 323 | * Synopsis 324 | * Options 325 | * Examples 326 | 327 | #### Synopsis 328 | Saves the running configuration to the Netscaler for the specified partition. 329 | 330 | #### Options 331 | 332 | | Parameter | required | default | choices | comments | 333 | | ------------- |-------------| ---------|----------- |--------- | 334 | 335 | 336 | 337 | 338 | 339 | --- 340 | 341 | 342 | ## netscaler_servicegroup 343 | Manages Service Group resources and attributes 344 | 345 | * Synopsis 346 | * Options 347 | * Examples 348 | 349 | #### Synopsis 350 | Manages Netscaler Service Group configurations using Nitro API 351 | 352 | #### Options 353 | 354 | | Parameter | required | default | choices | comments | 355 | | ------------- |-------------| ---------|----------- |--------- | 356 | | username | yes | | | The username used to authenticate with the Netscaler. | 357 | | comment | no | | | A comment about the servicegroup. | 358 | | servicegroup_state | no | enabled | | The servicegroup's desired activity. Disabled marks it out of service. Enabled marks it serviceable. | 359 | | server_timeout | no | | | Seconds to wait before terminating a server session. Valid inputs are from 0 to 31536000 | 360 | | servicegroup_name | yes | | | The name of the servicegroup object | 361 | | max_client | no | | | maximum number of simultaneous open connections Valid inputs are from 0 to 65535 | 362 | | traffic_domain | no | 0 | | The traffic domain associated with the servicegroup | 363 | | partition | no | | | The Netscaler's partition if not the "default" partition. | 364 | | state | no | present | | The desired state of the specified object. Absent will delete resource. Present will create resource. | 365 | | host | yes | | | The Netscaler's Address. | 366 | | max_req | no | | | maximum number of simultaneous open connections Valid inputs are from 0 to 65535 | 367 | | provider | no | | | Dictionary which acts as a collection of arguments used to define the characteristics of how to connect to the device. Arguments hostname, username, and password must be specified in either provider or local param. Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. | 368 | | service_type | no | | | The type of service associated with the bound vservers. must be included for new servicegroup objects. | 369 | | use_ssl | no | True | | Determines whether to use HTTPS(True) or HTTP(False). | 370 | | password | no | | | The password associated with the username account. | 371 | | validate_certs | no | False | | Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) | 372 | | port | no | | | The TCP port used to connect to the Netscaler if other than the default used by the transport method(http=80, https=443). | 373 | | client_timeout | no | | | Seconds to wait before terminating a client session. Valid inputs are from 0 to 31536000. | 374 | 375 | 376 | 377 | 378 | 379 | --- 380 | 381 | 382 | --- 383 | Created by Network to Code, LLC 384 | For: 385 | 2015 386 | -------------------------------------------------------------------------------- /library/netscaler_save_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # This file is part of Ansible 4 | # 5 | # Ansible is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # Ansible is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Ansible. If not, see . 17 | # 18 | 19 | ANSIBLE_METADATA = { 20 | "metadata_version": "1.0", 21 | "status": ["preview"], 22 | "supported_by": "community" 23 | } 24 | 25 | DOCUMENTATION = ''' 26 | --- 27 | module: netscaler_save_config 28 | version_added: "2.3" 29 | short_description: Saves the running configuration to the Netscaler 30 | description: 31 | - Saves the running configuration to the Netscaler for the specified partition. 32 | author: Jacob McGill (@jmcgill298) 33 | options: 34 | host: 35 | description: 36 | - The Netscaler's Address. 37 | required: true 38 | type: str 39 | partition: 40 | description: 41 | - The Netscaler's partition if not the "default" partition. 42 | required: false 43 | type: str 44 | password: 45 | description: 46 | - The password associated with the username account. 47 | required: false 48 | type: str 49 | port: 50 | description: 51 | - The TCP port used to connect to the Netscaler if other than the default used by the transport 52 | method(http=80, https=443). 53 | required: false 54 | type: int 55 | provider: 56 | description: 57 | - Dictionary which acts as a collection of arguments used to define the characteristics 58 | of how to connect to the device. 59 | - Arguments hostname, username, and password must be specified in either provider or local param. 60 | - Local params take precedence, e.g. hostname is preferred to provider["hostname"] when both are specefied. 61 | required: false 62 | type: dict 63 | use_ssl: 64 | description: 65 | - Determines whether to use HTTPS(True) or HTTP(False). 66 | required: false 67 | default: True 68 | type: bool 69 | username: 70 | description: 71 | - The username used to authenticate with the Netscaler. 72 | required: true 73 | type: str 74 | validate_certs: 75 | description: 76 | - Determines whether to validate certs against a trusted certificate file (True), or accept all certs (False) 77 | required: false 78 | default: False 79 | type: bool 80 | ''' 81 | 82 | EXAMPLES = ''' 83 | - name: Bind Service Group to Server 84 | netscaler_lbvserver: 85 | host: "{{ ansible_host }}" 86 | username: "{{ ansible_user }}" 87 | password: "{{ ansible_password }}" 88 | ''' 89 | 90 | RETURN = ''' 91 | status_code: 92 | description: The status code from the API request to save the Netscaler's configuration. 93 | returned: always 94 | type: str 95 | sample: 200 96 | logout: 97 | description: The result from closing the session with the Netscaler. True means successful logout; False means unsuccessful logout. 98 | returned: always 99 | type: bool 100 | sample: True 101 | ''' 102 | 103 | 104 | import requests 105 | from ansible.module_utils.basic import AnsibleModule, env_fallback, return_values 106 | 107 | requests.packages.urllib3.disable_warnings() 108 | 109 | 110 | class Netscaler(object): 111 | """ 112 | This is the Base Class for Netscaler modules. All methods common across several Netscaler Classes should be defined 113 | here and inherited by the sub-class. 114 | """ 115 | 116 | def __init__(self, host, user, passw, use_ssl=True, verify=False, api_endpoint="", **kwargs): 117 | """ 118 | :param host: Type str. 119 | The IP or resolvable hostname of the Netscaler. 120 | :param user: Type str. 121 | The username used to authenticate with the Netscaler. 122 | :param passw: Type str. 123 | The password associated with the user account. 124 | :param use_ssl: Type bool. 125 | The default is True, which uses HTTPS instead of HTTP. 126 | :param verify: Type bool. 127 | The default is False, which does not verify the certificate against the list of trusted 128 | certificates. 129 | :param api_endpoint: Type str. 130 | The API endpoint used for a particular configuration section. 131 | :param headers: Type dict. 132 | The headers to include in HTTP requests. 133 | :param kwargs: Type dict. Currently supports port. 134 | :param port: Type str. 135 | Passing the port parameter will override the default HTTP(S) port when making requests. 136 | """ 137 | self.host = host 138 | self.user = user 139 | self.passw = passw 140 | self.verify = verify 141 | self.api_endpoint = api_endpoint 142 | self.headers = {"Content-Type": "application/json"} 143 | if "port" not in kwargs: 144 | self.port = "" 145 | else: 146 | self.port = ":{}".format(kwargs["port"]) 147 | 148 | if use_ssl: 149 | self.url = "https://{lb}{port}/nitro/v1/config/".format(lb=self.host, port=self.port) 150 | self.stat_url = "https://{lb}{port}/nitro/v1/stat/".format(lb=self.host, port=self.port) 151 | else: 152 | self.url = "http://{lb}{port}/nitro/v1/config/".format(lb=self.host, port=self.port) 153 | self.stat_url = "http://{lb}{port}/nitro/v1/stat/".format(lb=self.host, port=self.port) 154 | 155 | def change_name(self, existing_name, proposed_name): 156 | """ 157 | The purpose of this method is to change the name of a server object. 158 | :param existing_name: Type str. 159 | The name of the server object to be renamed. 160 | :param proposed_name: Type str. 161 | The new name of the server object. 162 | :return: The response from the request to delete the object. 163 | """ 164 | url = self.url + self.api_endpoint + "?action=rename" 165 | body = {self.api_endpoint: {"name": existing_name, "newname":proposed_name}} 166 | response = self.session.post(url, json=body, headers=self.headers, verify=self.verify) 167 | 168 | return response 169 | 170 | def change_state(self, object_name, state): 171 | """ 172 | The purpose of this method is to change the state of an object from either disabled to enabled, or enabled to 173 | disabled. This method assumes the object is referenced by "name." This is the most common reference key, but not 174 | universal; where the Nitro API uses another key, an overriding method must be created in the sub-class. 175 | :param object_name: Type str. 176 | The name of the object to be deleted. 177 | :param state: Type str. 178 | The state the object should be in after execution. Valid values are "enable" or "disable" 179 | :return: The response from the request to delete the object. 180 | """ 181 | url = self.url + self.api_endpoint + "?action={}".format(state) 182 | body = {self.api_endpoint: {"name": object_name}} 183 | response = self.session.post(url, json=body, headers=self.headers, verify=self.verify) 184 | 185 | return response 186 | 187 | def config_delete(self, module, object_name): 188 | """ 189 | This method is used to handle the logic for Ansible modules when the "state" is set to "absent." The 190 | delete_config method is used to delete the object from the Netscaler. 191 | :param module: The AnsibleModule instance started by the task. 192 | :param object_name: Type str. 193 | The name of the object to be deleted. 194 | :return: The config dict corresponding to the config returned by the Ansible module. 195 | """ 196 | config = [] 197 | 198 | if not module.check_mode: 199 | config_status = self.delete_config(object_name) 200 | if config_status.ok: 201 | config.append({"method": "delete", "url": config_status.url, "body": {}}) 202 | else: 203 | logout = self.logout() 204 | module.fail_json(msg="Unable to Delete Object", netscaler_response=config_status.json(), logout=logout.ok) 205 | else: 206 | url = self.url + self.api_endpoint + "/" + object_name 207 | config.append({"method": "delete", "url": url, "body": {}}) 208 | 209 | return config 210 | 211 | def config_new(self, module, new_config): 212 | """ 213 | This method is used to handle the logic for Ansible modules when the "state" is set to "present" and the 214 | proposed config is a new object. The post_config method is used to post the object's configuration to the 215 | Netscaler. 216 | :param module: The AnsibleModule instance started by the task. 217 | :param new_config: Type dict. 218 | The configuration to send to the Nitro API. 219 | :return: A list with config dictionary corresponding to the config returned by the Ansible module. 220 | """ 221 | config = [] 222 | 223 | if not module.check_mode: 224 | config_status = self.post_config(new_config) 225 | if config_status.ok: 226 | config.append({"method": "post", "url": config_status.url, "body": new_config}) 227 | else: 228 | logout = self.logout() 229 | module.fail_json(msg="Unable to Add New Object", netscaler_response=config_status.json(), logout=logout.ok) 230 | else: 231 | config.append({"method": "post", "url": self.url + self.api_endpoint, "body": new_config}) 232 | 233 | return config 234 | 235 | def config_rename(self, module, existing_name, proposed_name): 236 | """ 237 | This method is used to handle the logic for Ansible modules when the "state" is set to "present" and the 238 | proposed IP Address matches the IP Address of another Server in the same Traffic Domain. The change_name 239 | method is used to post the configuration to the Netscaler. 240 | :param module: The AnsibleModule instance started by the task. 241 | :param existing_name: Type str. 242 | The current name of the Server object to be changed. 243 | :param proposed_name: Type str. 244 | The name the Server object should be changed to. 245 | :return: A list with config dictionary corresponding to the config returned by the Ansible module. 246 | """ 247 | config = [] 248 | 249 | rename_config = {"name": existing_name, "newname": proposed_name} 250 | 251 | if not module.check_mode: 252 | config_status = self.change_name(existing_name, proposed_name) 253 | if config_status.ok: 254 | config.append({"method": "post", "url": config_status.url, "body": rename_config}) 255 | else: 256 | logout = self.logout() 257 | module.fail_json(msg="Unable to Rename Object", netscaler_response=config_status.json(), logout=logout.ok) 258 | else: 259 | config.append({"method": "post", "url": self.url + self.api_endpoint + "?action=rename", "body": rename_config}) 260 | 261 | return config 262 | 263 | def config_update(self, module, update_config): 264 | """ 265 | This method is used to handle the logic for Ansible modules when the "state" is set to "present" and the 266 | proposed config modifies an existing object. If the object's state needs to be updated, the "state" key,value is 267 | popped from the update_config in order to prevent it from being included in a config update when there are 268 | updates besides state change. The change_state method is then used to modify the object's state. After the 269 | object's state matches the proposed state, a check is done to see if the update_config has any keys other than 270 | the "name" key (len > 1). If there are more updates to make, the put_config method is used to push those to the 271 | Netscaler. Note that this method uses the common "name" key to input to the change_state method; if the API 272 | Endpoint uses a different key, then an overriding method must be created in the sub-class. 273 | :param module: The AnsibleModule instance started by the task. 274 | :param update_config: Type dict. 275 | The configuration to send to the Nitro API. 276 | :return: The list of config dictionaries corresponding to the config returned by the Ansible module. 277 | """ 278 | config = [] 279 | 280 | if "state" in update_config: 281 | config_state = update_config.pop("state")[:-1].lower() 282 | if not module.check_mode: 283 | config_status = self.change_state(update_config["name"], config_state) 284 | if config_status.ok: 285 | config.append({"method": "post", "url": config_status.url, "body": {"name": update_config["name"]}}) 286 | else: 287 | logout = self.logout() 288 | module.fail_json(msg="Unable to Change Object's State", netscaler_response=config_status.json(), logout=logout.ok) 289 | else: 290 | url = self.url + self.api_endpoint + "?action={}".format(config_state) 291 | config.append({"method": "post", "url": url, "body": {"name": update_config["name"]}}) 292 | 293 | if len(update_config) > 1: 294 | if not module.check_mode: 295 | config_status = self.put_update(update_config) 296 | if config_status.ok: 297 | config.append({"method": "put", "url": self.url, "body": update_config}) 298 | else: 299 | logout = self.logout() 300 | module.fail_json(msg="Unable to Update Config", netscaler_response=config_status.json(), logout=logout.ok) 301 | else: 302 | config.append({"method": "put", "url": self.url, "body": update_config}) 303 | 304 | return config 305 | 306 | def delete_config(self, object_name): 307 | """ 308 | The purpose of this method is to remove an object from the Netscaler's configuration. Currently no checks are 309 | made to verify if the object is bound to another item. 310 | :param object_name: Type str. 311 | The name of the object to be deleted. 312 | :return: The response from the request to delete the object. 313 | """ 314 | url = self.url + self.api_endpoint + "/" + object_name 315 | response = self.session.delete(url, headers=self.headers, verify=self.verify) 316 | 317 | return response 318 | 319 | def get_all(self, api_endpoint): 320 | """ 321 | The purpose of this method is to retrieve every object's configuration for the API endpoint. 322 | :param api_endpoint: Type str. 323 | The API endpoint to use for data collection. 324 | :return: A list of configuration dictionaries returned by they Nitro API. An empty list means that their are 325 | currently no objects configured, or the request was unsuccessful. 326 | """ 327 | response = self.session.get(self.url + api_endpoint, headers=self.headers, verify=self.verify) 328 | 329 | return response.json().get(api_endpoint, []) 330 | 331 | def get_all_attrs(self, api_endpoint, attrs_list): 332 | """ 333 | The purpose of this method is to retrieve every object's configuration for the API endpoint, but the 334 | collected data is restricted to the attributes in the attrs_list argument. 335 | :param api_endpoint: Type str. 336 | The API endpoint to use for data collection. 337 | :param attrs_list: Type list,tuple 338 | The list of attributes used to limit the scope of returned config data. 339 | :return: A list of configuration dictionaries returned by they Nitro API. An empty list means that their are 340 | currently no objects configured, or the request was unsuccessful. 341 | """ 342 | attrs = "?attrs=" + ",".join(attrs_list) 343 | url = self.url + api_endpoint + attrs 344 | 345 | response = self.session.get(url, headers=self.headers, verify=self.verify) 346 | 347 | return response.json().get(api_endpoint, []) 348 | 349 | def get_config(self, defaults="false"): 350 | """ 351 | This method retrieves the running configuration from the Netscaler. 352 | :param defaults: Type str. 353 | The default setting will retrieve configurations that do not have their default setting. 354 | Setting this to "true" will retrieve the full configuration including defaults. 355 | :return: The configuration of the Netscaler as a str. An empty str is returned if the request is unsuccessful. 356 | """ 357 | url = self.url + "nsrunningconfig?args=withdefaults:{}".format(defaults) 358 | response = self.session.get(url, headers=self.headers, verify=self.verify) 359 | 360 | return response.json().get("nsrunningconfig", {"response": ""})["response"] 361 | 362 | @staticmethod 363 | def get_diff(proposed, existing): 364 | """ 365 | This method is used to compare the proposed config with what currently exists on the Netscaler. Note that thi 366 | method uses the most common key used by Nitro, "name." Where Nitro uses a different key, the corresponding class 367 | must have an overriding method. 368 | :param proposed: Type dict. 369 | A dictionary corresponding to the proposed configuration item. The dictionary must have a 370 | "name" key. 371 | :param existing: Type dict. 372 | A dictionary corresponding to the existing configuration for the object. This can be retrieved 373 | using the get_existing_attrs method. 374 | :return: A tuple indicating whether the config is a new object, will update an existing object, or make no 375 | changes, and a dict that corresponds to the body of a config request using the Nitro API. 376 | """ 377 | diff = dict(set(proposed.items()).difference(existing.items())) 378 | 379 | if diff == proposed: 380 | return "new", diff 381 | elif diff: 382 | diff["name"] = proposed["name"] 383 | return "update", diff 384 | else: 385 | return "none", {} 386 | 387 | def get_existing_attrs(self, object_name, attrs): 388 | """ 389 | This method is used to get a subset of a particular object's configuration for the given API Endpoint 390 | (configuration section). The configuration will be scoped to the list of values in attrs. 391 | :param object_name: Type str. 392 | The name of the object. 393 | :param attrs: Type list. 394 | The list of attributes to retrieve from the configuration. 395 | :return: A dictionary of the object's configuration. If the object doesn't exist or the request fails, then an 396 | empty dict is returned. Unexpected empty lists are likely caused by a mistyped API endpoint or an expired 397 | session. 398 | """ 399 | attributes = ",".join(attrs) 400 | url = self.url + self.api_endpoint + "/" + object_name + "?attrs=" + attributes 401 | response = self.session.get(url, headers=self.headers, verify=self.verify) 402 | 403 | return response.json().get(self.api_endpoint, [{}])[0] 404 | 405 | def get_hardware(self): 406 | """ 407 | This method is used to retrieve basic hardware information about the Netscaler. 408 | :return: A dictionary of hardware information. An empty dictionary is returned if the request is unsuccessful. 409 | """ 410 | response = self.session.get(self.url + "nshardware", headers=self.headers, verify=self.verify) 411 | 412 | return response.json().get("nshardware", {}) 413 | 414 | def get_hostname(self): 415 | """ 416 | This method is used to retrieve the hostname of the connected Netscaler 417 | :return: A dictionary of the hostname configuration. An empty dictionary is returned if the API request failed. 418 | """ 419 | response = self.session.get(self.url + "nshostname", headers=self.headers, verify=self.verify) 420 | 421 | return response.json().get("nshostname", [{}])[0] 422 | 423 | def get_interfaces(self): 424 | """ 425 | This method is used to get the interfaces and their stats from the Netscaler. 426 | :return: A list of interface dictionaries containing configuration and statistical info. An empty list is 427 | returned if the request is unsuccessful. 428 | """ 429 | response = self.session.get(self.url + "interface", headers=self.headers, verify=self.verify) 430 | 431 | return response.json().get("Interface", []) 432 | 433 | def get_lbvserver_stats(self): 434 | """ 435 | This method is used to get the lbvserver statistical info for all vservers on the Netscaler. 436 | :return: A list of dictionaries for all statistical data for the lbvservers. An empty dictionary is returned if 437 | the request is unsuccessful. 438 | """ 439 | response = self.session.get(self.stat_url + "lbvserver", headers=self.headers, verify=self.verify) 440 | 441 | return response.json().get("lbvserver", []) 442 | 443 | def get_nsconfig(self): 444 | """ 445 | This method is used to get the nsconfig data from the Netscaler. 446 | :return: A dictionary of the nsconfig data. An empty dictionary is returned if the request is unsuccessful. 447 | """ 448 | response = self.session.get(self.url + "nsconfig", headers=self.headers, verify=self.verify) 449 | 450 | return response.json().get("nsconfig", {}) 451 | 452 | def get_state(self, object_name): 453 | """ 454 | This method is used to retrieve the current state of the object. The possibilities are enabled or disabled. 455 | :param object_name: Type str. 456 | The name of the object. 457 | :return: A str representing the current state of the object. An empty string is returned when the object does 458 | not exist. 459 | """ 460 | url = self.url + self.api_endpoint + object_name + "attrs=state" 461 | response = self.session.get(url, headers=self.headers, verify=self.verify) 462 | 463 | return response.json().get(self.api_endpoint, [{"state": ""}])[0]["state"] 464 | 465 | def get_system(self): 466 | """ 467 | This method is used to retrieve the system or environment statistics from the Netscaler. 468 | :return: A dictionary of the systems statistics (fans, memory, cpu, temp, disk space). An empty dictionary is 469 | returned if the request is unsuccessful. 470 | """ 471 | response = self.session.get(self.stat_url + "system", headers=self.headers, verify=self.verify) 472 | 473 | return response.json().get("system", {}) 474 | 475 | def login(self): 476 | """ 477 | The login method is used to establish a session with the Netscaler. All necessary parameters need to be 478 | established at class instantiation. The requests Session class is used to maintain session consistency for all 479 | subsequent requests. The Session class automatically stores the cookie returned from the login request, and 480 | passes the cookie on all requests after a successful login. This is important when using partitions since the 481 | Netscaler API (Nitro) does not support modifying partitions using basic auth. Note that using partitions still 482 | requires calling the switch_partition function; these are separated so as to separate the failure domains. 483 | :return: The response from the login request. A successful login also sets the instance session. 484 | """ 485 | url = self.url + "login" 486 | body = {"login": {"username": self.user, "password": self.passw}} 487 | session = requests.Session() 488 | login = session.post(url, json=body, headers=self.headers, verify=self.verify) 489 | 490 | if login.ok: 491 | self.session = session 492 | 493 | return login 494 | 495 | def logout(self): 496 | """ 497 | The logout method is used to close the established connection with the Netscaler device. 498 | :return: The response from the logout request. 499 | """ 500 | url = self.url + "logout" 501 | body = {"logout": {}} 502 | logout = self.session.post(url, json=body, headers=self.headers, verify=self.verify) 503 | 504 | return logout 505 | 506 | def post_config(self, new_config): 507 | """ 508 | This method is used to submit a configuration request to the Netscaler using the Nitro API. 509 | :param new_config: Type dict: 510 | The new configuration item to be sent to the Netscaler. It is expected that you use the 511 | get_diff method to generate the new_config data. 512 | :return: The response from the request to add the configuration. 513 | """ 514 | url = self.url + self.api_endpoint 515 | body = {self.api_endpoint: new_config} 516 | response = self.session.post(url, json=body, headers=self.headers, verify=self.verify) 517 | 518 | return response 519 | 520 | def put_update(self, update_config): 521 | """ 522 | This method is used to update the configuration of an existing item on the Netscaler. 523 | :param update_config: Type dict: 524 | The configuration item to be sent to the Netscaler in order to update existing object. It 525 | is expected that you use the get_diff method to generate the update_config data. 526 | :return: The response from the request to add the configuration. 527 | """ 528 | url = self.url + self.api_endpoint 529 | body = {self.api_endpoint: update_config} 530 | response = self.session.put(url, json=body, headers=self.headers, verify=self.verify) 531 | 532 | return response 533 | 534 | def save_config(self): 535 | """ 536 | This method is used to save the config of the Netscaler. 537 | :return: The response from the request to save the config. 538 | """ 539 | url = self.url + "nsconfig?action=save" 540 | response = self.session.post(url, json={"nsconfig": {}}, headers=self.headers, verify=self.verify) 541 | 542 | return response 543 | 544 | def switch_partition(self, partition): 545 | """ 546 | This method will switch from the default partition to the specified partition. 547 | :param partition: Type str. 548 | The partition to interact with for all subsequent requests. 549 | :return: The response from the request to switch partitions. 550 | """ 551 | url = self.url + "nspartition?action=Switch" 552 | body = {"nspartition": {"partitionname": partition}} 553 | switch = self.session.post(url, json=body, headers=self.headers, verify=self.verify) 554 | 555 | return switch 556 | 557 | @staticmethod 558 | def validate_ip(ip_address): 559 | """ 560 | This method is used to validate that an IPv4 Address has 4 octets and that each octet is an int from 0 to 255. 561 | Note, "0.0.0.0" is a valid IP. 562 | :param ip_address: Type str. 563 | An IPv4 address. 564 | :return: A valid IP returns True; otherwise, False. 565 | """ 566 | octet_split = ip_address.split(".") 567 | if len(octet_split) != 4: 568 | return False 569 | 570 | for octet in octet_split: 571 | try: 572 | int_octet = int(octet) 573 | except ValueError: 574 | return False 575 | 576 | if 0 > int_octet or 255 < int_octet: 577 | return False 578 | 579 | return True 580 | 581 | 582 | def main(): 583 | argument_spec = dict( 584 | host=dict(required=False, type="str"), 585 | port=dict(required=False, type="int"), 586 | username=dict(fallback=(env_fallback, ["ANSIBLE_NET_USERNAME"])), 587 | password=dict(fallback=(env_fallback, ["ANSIBLE_NET_PASSWORD"]), no_log=True), 588 | use_ssl=dict(required=False, type="bool"), 589 | validate_certs=dict(required=False, type="bool"), 590 | provider=dict(required=False, type="dict"), 591 | partition=dict(required=False, type="str"), 592 | ) 593 | 594 | module = AnsibleModule(argument_spec, supports_check_mode=False) 595 | provider = module.params["provider"] or {} 596 | 597 | no_log = ["password"] 598 | for param in no_log: 599 | if provider.get(param): 600 | module.no_log_values.update(return_values(provider[param])) 601 | 602 | # allow local params to override provider 603 | for param, pvalue in provider.items(): 604 | if module.params.get(param) is None: 605 | module.params[param] = pvalue 606 | 607 | host = module.params["host"] 608 | partition = module.params["partition"] 609 | password = module.params["password"] 610 | port = module.params["port"] 611 | use_ssl = module.params["use_ssl"] 612 | if use_ssl is None: 613 | use_ssl = True 614 | username = module.params["username"] 615 | validate_certs = module.params["validate_certs"] 616 | if validate_certs is None: 617 | validate_certs = False 618 | 619 | # check for required values, this allows all values to be passed in provider 620 | argument_check = dict(host=host) 621 | for key, val in argument_check.items(): 622 | if not val: 623 | module.fail_json(msg="The {} parameter is required".format(key)) 624 | 625 | kwargs = dict() 626 | if port: 627 | kwargs["port"] = port 628 | 629 | session = Netscaler(host, username, password, use_ssl, validate_certs, **kwargs) 630 | session_login = session.login() 631 | if not session_login.ok: 632 | module.fail_json(msg="Unable to Login", netscaler_response=session_login.json()) 633 | 634 | if partition: 635 | session_switch = session.switch_partition(partition) 636 | if not session_switch.ok: 637 | session_logout = session.logout() 638 | module.fail_json(msg="Unable to Switch Partitions", netscaler_response=session_switch.json(), logout=session_logout.ok) 639 | 640 | response = session.save_config() 641 | 642 | if response.ok: 643 | results = dict(changed=True, status_code=response.status_code) 644 | else: 645 | session_logout = session.logout() 646 | module.fail_json(msg="Unable to Save the Configuration", netscaler_response=response.json(), logout=session_logout.ok) 647 | 648 | session_logout = session.logout() 649 | results["logout"] = session_logout.ok 650 | 651 | return module.exit_json(**results) 652 | 653 | 654 | if __name__ == "__main__": 655 | main() 656 | --------------------------------------------------------------------------------