Skip to content

Commit

Permalink
added support to configure ADC via NetScaler Console (ADM) as proxy
Browse files Browse the repository at this point in the history
Signed-off-by: Sumanth Lingappa <sumanth.lingappa@cloud.com>
  • Loading branch information
sumanth-lingappa committed Apr 19, 2024
1 parent b4de90d commit c33a053
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 10 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.6.0] - 2024-04-19

### Added

- Added support to configure NetScaler via NetScaler Console (ADM) as Proxy server ([#308])

## [2.5.2] - 2024-04-15

### Fixed
Expand Down Expand Up @@ -116,7 +122,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Initial Release

[unreleased]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.5.2...HEAD
[unreleased]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.6.0...HEAD
[2.6.0]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.5.2...2.6.0
[2.5.2]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.5.1...2.5.2
[2.5.1]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.5.0...2.5.1
[2.5.0]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.4.0...2.5.0
Expand All @@ -134,6 +141,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#295]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/295
[#297]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/297
[#307]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/307
[#308]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/308
[#310]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/310
[#311]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/311
[#312]: https://github.com/netscaler/ansible-collection-netscaleradc/issues/312
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ export NETSCALER_NITRO_AUTH_TOKEN=$(curl -X POST -H "Content-Type:application/js
echo $NETSCALER_NITRO_AUTH_TOKEN
```

## NetScaler Console (ADM) as a Proxy Server

Refer to the [NetScaler ADM as an API proxy server](https://docs.netscaler.com/en-us/citrix-application-delivery-management-software/current-release/adm-as-api-proxy-server.html) for more details.

The collection supports configuring NetScaler Console as a proxy server. This is useful when you have multiple NetScaler ADC appliances and you want to manage them using a single NetScaler Console.

An example can be found in [examples/netscaler_console_as_proxy_server.yaml](examples/netscaler_console_as_proxy_server.yaml)

Also, refer to the [playbook_anatomy.md](playbook_anatomy.md#netscaler-console-as-an-api-proxy-server) for more details.

### Steps to configure NetScaler Console as a proxy server

1. Login to NetScaler Console and get the session ID
2. Use the session ID in the subsequent tasks to configure the managed NetScalers via the NetScaler Console as a proxy server
3. Logout from the NetScaler Console (optional)

## Supported Ansible Versions

This collection is tested for Ansible version 2.14 and above.
Expand Down
49 changes: 49 additions & 0 deletions examples/netscaler_console_as_proxy_server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
- name: Sample Playbook to demonstrate the usage of netscaler console as proxy server to configure the managed device
hosts: localhost
gather_facts: false
tasks:
- name: Sample Task | login
delegate_to: localhost
register: login_result
netscaler.adc.login:
nsip: "{{ lookup('env', 'NETSCALER_CONSOLE_IP') }}"
nitro_protocol: http
validate_certs: false
# If this is false, then the `login` request will be sent to the ADC instead of the Console
netscaler_console_as_proxy_server: true
managed_netscaler_instance_ip: "{{ lookup('env', 'NETSCALER_NSIP') }}"
managed_netscaler_instance_username: "{{ lookup('env', 'NETSCALER_NITRO_USER') }}"
managed_netscaler_instance_password: "{{ lookup('env', 'NETSCALER_NITRO_PASS') }}"
username: "{{ lookup('env', 'NETSCALER_CONSOLE_USER') }}"
password: "{{ lookup('env', 'NETSCALER_CONSOLE_PASS') }}"
- name: Print login sessionid
ansible.builtin.debug:
var: login_result.sessionid
- name: Sample Task | nsip
delegate_to: localhost
netscaler.adc.nsip:
nsip: "{{ lookup('env', 'NETSCALER_CONSOLE_IP') }}"
nitro_protocol: http
validate_certs: false
netscaler_console_as_proxy_server: true
managed_netscaler_instance_ip: "{{ lookup('env', 'NETSCALER_NSIP') }}"
managed_netscaler_instance_username: "{{ lookup('env', 'NETSCALER_NITRO_USER') }}"
managed_netscaler_instance_password: "{{ lookup('env', 'NETSCALER_NITRO_PASS') }}"
nitro_auth_token: "{{ login_result.sessionid }}"
state: present
ipaddress: 4.4.4.4
netmask: 255.255.255.192
type: VIP
- name: Sample Task | logout
delegate_to: localhost
netscaler.adc.logout:
nsip: "{{ lookup('env', 'NETSCALER_CONSOLE_IP') }}"
nitro_protocol: http
validate_certs: false
# If this is false, then the `logout` request will be sent to the ADC instead of the Console
netscaler_console_as_proxy_server: true
managed_netscaler_instance_ip: "{{ lookup('env', 'NETSCALER_NSIP') }}"
managed_netscaler_instance_username: "{{ lookup('env', 'NETSCALER_NITRO_USER') }}"
managed_netscaler_instance_password: "{{ lookup('env', 'NETSCALER_NITRO_PASS') }}"
nitro_auth_token: "{{ login_result.sessionid }}"
2 changes: 1 addition & 1 deletion galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace: netscaler
# The name of the collection. Has the same character restrictions as 'namespace'
name: adc
# The version of the collection. Must be compatible with semantic versioning
version: 2.5.2
version: 2.6.0
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md
# A list of the collection's content authors. Can be just the name or in the format 'Full Name <email> (url)
Expand Down
33 changes: 33 additions & 0 deletions playbook_anatomy.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# `netscaler.adc` collection playbook anatomy


## Anatomy of a playbook

This is how a typical playbook for `netscaler.adc` collection looks like:

```yaml
Expand All @@ -16,6 +19,12 @@ This is how a typical playbook for `netscaler.adc` collection looks like:
nitro_protocol: http
validate_certs: false
save_config: false
netscaler_console_as_proxy_server: true
managed_netscaler_instance_name: my_instance
managed_netscaler_instance_id: 1234
managed_netscaler_instance_ip: 1.1.1.1
managed_netscaler_instance_username: my_user
managed_netscaler_instance_password: my_password

tasks:
- name: Name of the task
Expand All @@ -29,6 +38,17 @@ This is how a typical playbook for `netscaler.adc` collection looks like:
nitro_protocol: https # This can also be given via NETSCALER_NITRO_PROTOCOL environment variable
validate_certs: false # This can also be given via NETSCALER_VALIDATE_CERTS environment variable

# NetScaler Console as an API Proxy Server. This is optional. Default is false.
# Refer: https://docs.netscaler.com/en-us/netscaler-application-delivery-management-software/current-release/adm-as-api-proxy-server.html
netscaler_console_as_proxy_server: true # This can also be given via NETSCALER_CONSOLE_AS_PROXY_SERVER environment variable
# When you want NetScaler Console to forward a request to a managed netscaler instance, add ANY ONE of the below parameters.
managed_netscaler_instance_name: my_instance # This can also be given via NETSCALER_MANAGED_NETSCALER_INSTANCE_NAME environment variable
managed_netscaler_instance_id: 1234 # This can also be given via NETSCALER_MANAGED_NETSCALER_INSTANCE_ID environment variable
managed_netscaler_instance_ip: 1.1.1.1 # This can also be given via NETSCALER_MANAGED_NETSCALER_INSTANCE_IP environment variable
# In Settings > Administration > System Configurations > Basic Settings, if you select Prompt Credentials for Instance Login, ensure to configure user name and password of a managed instance. Alternatively, you can also specify the instance session ID.
managed_netscaler_instance_username: my_user # This can also be given via NETSCALER_MANAGED_NETSCALER_INSTANCE_USERNAME environment variable
managed_netscaler_instance_password: my_password # This can also be given via NETSCALER_MANAGED_NETSCALER_INSTANCE_PASSWORD environment variable

# Should the module save the config after making the changes. This is optional. Default is false.
save_config: false # This can also be given via NETSCALER_SAVE_CONFIG environment variable

Expand All @@ -49,4 +69,17 @@ This is how a typical playbook for `netscaler.adc` collection looks like:
- `validate_certs` is optional. If it is not given, the module will try to read the value from the environment variable `NETSCALER_VALIDATE_CERTS`. If the environment variable is not set, the module will use `true`.
- `nsip` is required. If it is not given, the module will try to read the value from the environment variable `NETSCALER_NSIP`. If the environment variable is not set, the module will fail.
- `module_defaults`: Refer [`netscaler.adc.module_defaults` group](https://github.com/netscaler/ansible-collection-netscaleradc/tree/main?tab=readme-ov-file#using-netscaleradcmodule_defaults-group) for more details

## NetScaler Console as an API Proxy Server

- `netscaler_console_as_proxy_server`: This is optional. Default is `false`. Refer [NetScaler Console as an API Proxy Server](https://docs.netscaler.com/en-us/netscaler-application-delivery-management-software/current-release/adm-as-api-proxy-server.html) for more details.
- `managed_netscaler_instance_name`, `managed_netscaler_instance_id`, `managed_netscaler_instance_ip`: When you want NetScaler Console to forward a request to a managed netscaler instance, add ANY ONE of these parameters.
- `managed_netscaler_instance_username`, `managed_netscaler_instance_password`: In **Settings > Administration > System Configurations > Basic Settings**, if you select **Prompt Credentials for Instance Login**, ensure to configure username and password of a managed instance.

## State parameter

- `state`: Refer [modes of operation](https://github.com/netscaler/ansible-collection-netscaleradc/blob/main/features_v2.md#modes-of-operation-state-option-in-the-module-task) for more details

## Module parameters

Click on the resource in [the supported module matrix table](./supported_modules_matrix.md#matrix) for the module parameters.
39 changes: 39 additions & 0 deletions plugins/doc_fragments/netscaler_adc.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,45 @@ class ModuleDocFragment(object):
- Base NITRO API path.
- Define only in case of an ADM service proxy call
default: "nitro/v1/config"
netscaler_console_as_proxy_server:
type: bool
description:
- The IP address of the NetScaler ADC appliance acting as a proxy server.
- Define only in case of an ADM service proxy call
managed_netscaler_instance_name:
type: str
description:
- The name of the managed NetScaler instance to which NetScaler Console
- has to configure as a proxy server.
- Define only in case of an ADM service proxy call
managed_netscaler_instance_ip:
type: str
description:
- The IP of the managed NetScaler instance to which NetScaler Console
- has to configure as a proxy server.
- Define only in case of an ADM service proxy call
managed_netscaler_instance_id:
type: str
description:
- The ID of the managed NetScaler instance to which NetScaler Console
- has to configure as a proxy server.
- Define only in case of an ADM service proxy call
managed_netscaler_instance_username:
type: str
description:
- The username of the managed NetScaler instance.
- Define only in case of an ADM service proxy call
- In Settings > Administration > System Configurations > Basic Settings,
- if you select Prompt Credentials for Instance Login,
- ensure to configure username and password of a managed instance.
managed_netscaler_instance_password:
type: str
description:
- The password of the managed NetScaler instance.
- Define only in case of an ADM service proxy call
- In Settings > Administration > System Configurations > Basic Settings,
- if you select Prompt Credentials for Instance Login,
- ensure to configure username and password of a managed instance.
notes:
- For more information on using Ansible to manage NetScaler ADC Network devices see U(https://www.ansible.com/integrations/networks/citrixadc).
Expand Down
34 changes: 34 additions & 0 deletions plugins/module_utils/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,33 @@ def __init__(self, module):
self._headers["X-NITRO-USER"] = self._module.params["nitro_user"]
self._headers["X-NITRO-PASS"] = self._module.params["nitro_pass"]

# Do header manipulation when using NetScaler Console (ADM) as proxy
# Refer: https://docs.netscaler.com/en-us/netscaler-application-delivery-management-software/current-release/adm-as-api-proxy-server.html
netscaler_console_as_proxy = self._module.params.get(
"netscaler_console_as_proxy_server"
)
if netscaler_console_as_proxy:
if self._module.params.get("managed_netscaler_instance_name"):
self._headers[
"_MPS_API_PROXY_MANAGED_INSTANCE_NAME"
] = self._module.params.get("managed_netscaler_instance_name")
if self._module.params.get("managed_netscaler_instance_ip"):
self._headers[
"_MPS_API_PROXY_MANAGED_INSTANCE_IP"
] = self._module.params.get("managed_netscaler_instance_ip")
if self._module.params.get("managed_netscaler_instance_id"):
self._headers[
"_MPS_API_PROXY_MANAGED_INSTANCE_ID"
] = self._module.params.get("managed_netscaler_instance_id")
if self._module.params.get("managed_netscaler_instance_username"):
self._headers[
"_MPS_API_PROXY_MANAGED_INSTANCE_USERNAME"
] = self._module.params.get("managed_netscaler_instance_username")
if self._module.params.get("managed_netscaler_instance_password"):
self._headers[
"_MPS_API_PROXY_MANAGED_INSTANCE_PASSWORD"
] = self._module.params.get("managed_netscaler_instance_password")

@trace
def url_builder(
self,
Expand Down Expand Up @@ -193,6 +220,13 @@ def post(self, post_data, resource, action=None):
self._headers.pop("X-NITRO-USER", None)
self._headers.pop("X-NITRO-PASS", None)
self._headers.pop("Cookie", None)
if resource in {"login", "logout"}:
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_NAME", None)
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_IP", None)
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_ID", None)
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_USERNAME", None)
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_PASSWORD", None)
self._headers.pop("_MPS_API_PROXY_MANAGED_INSTANCE_SESSID", None)
return self.send("POST", url, data)

@trace
Expand Down
2 changes: 2 additions & 0 deletions plugins/module_utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ def adc_logout(client):
post_data = {
"logout": {},
}
if client._module.params["netscaler_console_as_proxy_server"]:
post_data["logout"]["sessionid"] = client._module.params["nitro_auth_token"]
status_code, response_body = client.post(
post_data=post_data,
resource="logout",
Expand Down
32 changes: 32 additions & 0 deletions plugins/module_utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,36 @@
required=False,
default="nitro/v1/config",
),
netscaler_console_as_proxy_server=dict(
type="bool",
required=False,
default=False,
fallback=(env_fallback, ["NETSCALER_CONSOLE_AS_PROXY_SERVER"]),
),
managed_netscaler_instance_name=dict(
type="str",
required=False,
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_NAME"]),
),
managed_netscaler_instance_ip=dict(
type="str",
required=False,
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_IP"]),
),
managed_netscaler_instance_id=dict(
type="str",
required=False,
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_ID"]),
),
managed_netscaler_instance_username=dict(
type="str",
required=False,
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_USERNAME"]),
),
managed_netscaler_instance_password=dict(
type="str",
required=False,
no_log=True,
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_PASSWORD"]),
),
)
54 changes: 46 additions & 8 deletions plugins/module_utils/module_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,54 @@ def __init__(self, resource_name, supports_check_mode=True):
self.module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=supports_check_mode,
# mutually_exclusive=[
# ("nitro_auth_token", "nitro_user"),
# ("nitro_auth_token", "nitro_pass"),
# ],
# required_together=[
# ("nitro_user", "nitro_pass"),
# ],
mutually_exclusive=[
# ("nitro_auth_token", "nitro_user"),
# ("nitro_auth_token", "nitro_pass"),
(
"managed_netscaler_instance_name",
"managed_netscaler_instance_ip",
"managed_netscaler_instance_id",
),
],
required_together=[
("nitro_user", "nitro_pass"),
(
"managed_netscaler_instance_username",
"managed_netscaler_instance_password",
),
],
# required_one_of=[
# ("nitro_auth_token", "nitro_user"),
# ("nitro_auth_token", "nitro_pass"),
# ],
required_if=[
(
"netscaler_console_as_proxy_server",
True,
(
"managed_netscaler_instance_name",
"managed_netscaler_instance_ip",
"managed_netscaler_instance_id",
"managed_netscaler_instance_username",
"managed_netscaler_instance_password",
),
True,
),
],
# required_by= {
# }
)

self.netscaler_console_as_proxy_server = self.module.params[
"netscaler_console_as_proxy_server"
]

if self.netscaler_console_as_proxy_server and self.resource_name in {
"login",
"logout",
}:
self.module.params["api_path"] = "nitro/v2/config"

self.client = NitroAPIClient(self.module)
self.ns_major_version, self.ns_minor_version = get_netscaler_version(
self.client
Expand Down Expand Up @@ -782,7 +817,10 @@ def login(self):
self.return_failure(response_body)

self.module_result["changed"] = True
self.sessionid = response_body["sessionid"]
if self.netscaler_console_as_proxy_server:
self.sessionid = response_body[self.resource_name][0]["sessionid"]
else:
self.sessionid = response_body["sessionid"]
self.return_success()
except Exception as e:
msg = "Exception %s: %s" % (type(e), str(e))
Expand Down

0 comments on commit c33a053

Please sign in to comment.