Skip to content

Commit 8f43fcb

Browse files
Merge branch 'main' into NSNETAUTO_1005_bgprouter
2 parents 585bc45 + 616ee6f commit 8f43fcb

File tree

12 files changed

+699
-20
lines changed

12 files changed

+699
-20
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
.vscode/
22

3-
tools/
43
issues/
54

65
plugins/module_utils/test.ipynb

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [2.10.0] - 2025-08-22
11+
12+
### Added
13+
14+
- Added migration tool to convert `citrix.adc` module playbooks to `netscaler.adc`.
15+
16+
### Fixed
17+
18+
- Added option to skip non-updatable resources or fail explicitly
19+
- Removal of basic authentication from Netscaler ADC Ansible collection
20+
- Fixed idempotency issue in rename operations
21+
- Fixed GET request URL for global bindings to include type query parameter
22+
1023
## [2.9.2] - 2025-06-25
1124

1225
### Fixed
@@ -177,7 +190,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
177190
### Added
178191

179192
- Initial Release
180-
[unreleased]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.9.2...HEAD
193+
[unreleased]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.10.0...HEAD
194+
[2.10.0]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.9.2...2.10.0
181195
[2.9.2]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.9.1...2.9.2
182196
[2.9.1]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.9.0...2.9.1
183197
[2.9.0]: https://github.com/netscaler/ansible-collection-netscaleradc/compare/2.8.0...2.9.0

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ fmt:
22
autoflake plugins/modules/*.py
33
autoflake plugins/module_utils/*.py
44
autoflake --recursive tests/
5+
autoflake migrationtool/*py
56

67
black plugins/modules/*.py
78
black plugins/module_utils/*.py
89
black tests/
10+
black migrationtool/*.py
911

1012
isort plugins/modules/*.py
1113
isort plugins/module_utils/*.py
1214
isort tests/
15+
isort migrationtool/*.py
1316

1417
yamlfmt .
1518

@@ -39,7 +42,7 @@ build:
3942
ansible-galaxy collection build --force
4043

4144
galaxy_importer: build
42-
python3 -m galaxy_importer.main netscaler-adc-2.9.1.tar.gz
45+
python3 -m galaxy_importer.main netscaler-adc-2.10.0.tar.gz
4346

4447
# build_docs:
4548
# rm -rf _built_docs

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,62 @@ export NETSCALER_NITRO_AUTH_TOKEN=$(curl -X POST -H "Content-Type:application/js
157157
echo $echo $NETSCALER_NITRO_AUTH_TOKEN
158158
```
159159

160+
### Migration Tool
161+
162+
The collection includes a migration tool to help convert existing Ansible playbooks from the legacy `citrix.adc` collection to the new `netscaler.adc` collection format. This tool simplifies the transition from legacy automation to the updated collection.
163+
164+
#### Features
165+
166+
- **Module Mapping**: Automatically converts `citrix.adc` modules to `netscaler.adc` modules
167+
- **NITRO Request Conversion**: Transforms `citrix_adc_nitro_request` tasks to specific resource modules
168+
- **State Conversion**: Maps legacy operations (`add`, `update`, `delete`) to appropriate state values
169+
- **Credential Preservation**: Maintains authentication parameters and playbook structure
170+
- **YAML Structure Preservation**: Keeps task names, variables, and organization intact
171+
172+
#### Usage
173+
174+
```bash
175+
# Basic conversion
176+
python3 migrationtool/convert_yaml.py -i legacy_playbook.yaml -o migrated_playbook.yaml
177+
178+
# With verbose output
179+
python3 migrationtool/convert_yaml.py -i legacy_playbook.yaml -o migrated_playbook.yaml -v
180+
```
181+
182+
#### Example Conversion
183+
184+
**Before (Legacy citrix.adc):**
185+
```yaml
186+
- name: Configure LB vserver
187+
citrix_adc_nitro_request:
188+
nsip: "{{ nsip }}"
189+
nitro_user: "{{ nitro_user }}"
190+
nitro_pass: "{{ nitro_pass }}"
191+
operation: add
192+
resource: lbvserver
193+
name: my_lb_vserver
194+
attributes:
195+
servicetype: HTTP
196+
ipv46: 10.10.10.10
197+
port: 80
198+
```
199+
200+
**After (New netscaler.adc):**
201+
```yaml
202+
- name: Configure LB vserver
203+
netscaler.adc.lbvserver:
204+
nsip: "{{ nsip }}"
205+
nitro_user: "{{ nitro_user }}"
206+
nitro_pass: "{{ nitro_pass }}"
207+
state: present
208+
name: my_lb_vserver
209+
servicetype: HTTP
210+
ipv46: 10.10.10.10
211+
port: 80
212+
```
213+
214+
For detailed migration tool documentation, usage examples, and troubleshooting, refer to the [Migration Tool README](https://github.com/netscaler/ansible-collection-netscaleradc/blob/main/migrationtool/README.md).
215+
160216
### Invocation
161217

162218
The credentials of the netscaler can be provided either in the playbook by hardcoding or defining in a inventory.ini file.

galaxy.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace: netscaler
77
# The name of the collection. Has the same character restrictions as 'namespace'
88
name: adc
99
# The version of the collection. Must be compatible with semantic versioning
10-
version: 2.9.2
10+
version: 2.10.0
1111
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
1212
readme: README.md
1313
# A list of the collection's content authors. Can be just the name or in the format 'Full Name <email> (url)
@@ -58,7 +58,6 @@ build_ignore:
5858
- ".DS_Store"
5959
- "docs"
6060
- "examples"
61-
- "tools"
6261
- "issues"
6362
- "**/netscaler-adc-*.tar.gz"
6463
- "Makefile"

plugins/module_utils/common.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
HTTP_RESOURCE_NOT_FOUND,
1515
HTTP_SUCCESS_CODES,
1616
NESTED_POST_DATA_RESOURCES,
17+
GLOBAL_BINDING_ARG_LIST
1718
)
1819
from .decorators import trace
1920
from .logger import log
@@ -61,11 +62,21 @@ def get_resource(client, resource_name, resource_id=None, resource_module_params
6162

6263
if resource_name.endswith("_binding"):
6364
# binding resources require `filter` instead of `args` to uniquely identify a resource
64-
status_code, response_body = client.get(
65-
resource=resource_name,
66-
id=resource_id,
67-
filter=get_args,
68-
)
65+
if resource_name in GLOBAL_BINDING_ARG_LIST:
66+
# here we are making sure that for globalbindings present in the list query params args=type and filter=get_arg_keys
67+
del get_args["type"]
68+
status_code, response_body = client.get(
69+
resource=resource_name,
70+
id=resource_id,
71+
filter=get_args,
72+
args={"type": resource_module_params["type"]},
73+
)
74+
else:
75+
status_code, response_body = client.get(
76+
resource=resource_name,
77+
id=resource_id,
78+
filter=get_args,
79+
)
6980
elif resource_name in {"sslcertfile"}:
7081
status_code, response_body = client.get(
7182
resource=resource_name,

plugins/module_utils/constants.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,40 @@
116116
fallback=(env_fallback, ["MANAGED_NETSCALER_INSTANCE_PASSWORD"]),
117117
),
118118
)
119+
120+
# this list contains globalbindings whose GET call must have query params args=type and filter=get_arg_keys (check in nitro_resource_map)
121+
GLOBAL_BINDING_ARG_LIST = [
122+
'dnsglobal_dnspolicy_binding',
123+
'responderglobal_responderpolicy_binding',
124+
'contentinspectionglobal_contentinspectionpolicy_binding',
125+
'appflowglobal_appflowpolicy_binding',
126+
'appfwglobal_auditnslogpolicy_binding',
127+
'appfwglobal_auditsyslogpolicy_binding',
128+
'appfwglobal_appfwpolicy_binding',
129+
'rewriteglobal_rewritepolicy_binding',
130+
'transformglobal_transformpolicy_binding',
131+
'sslglobal_sslpolicy_binding',
132+
'tunnelglobal_tunneltrafficpolicy_binding',
133+
'cmpglobal_cmppolicy_binding',
134+
'feoglobal_feopolicy_binding',
135+
'icaglobal_icapolicy_binding',
136+
'lbglobal_lbpolicy_binding',
137+
'cacheglobal_cachepolicy_binding',
138+
'botglobal_botpolicy_binding',
139+
]
140+
141+
GETALL_ONLY_RESOURCES = [
142+
'appfwlearningdata',
143+
'application',
144+
'bridgetable',
145+
'gslbldnsentry',
146+
'locationfile',
147+
'locationfile6',
148+
'routerdynamicrouting',
149+
'sslcertbundle',
150+
'sslcertfile',
151+
'sslcrlfile',
152+
'ssldhfile',
153+
'sslkeyfile',
154+
'systementitydata'
155+
]

plugins/module_utils/module_executor.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
NETSCALER_COMMON_ARGUMENTS,
4040
NITRO_ATTRIBUTES_ALIASES,
4141
NESTED_POST_DATA_RESOURCES,
42+
GETALL_ONLY_RESOURCES,
4243
)
4344
from .decorators import trace
4445
from .logger import log, loglines
@@ -322,17 +323,31 @@ def get_existing_resource(self):
322323
if is_exist is False:
323324
return {}
324325
if len(existing_resource) > 1:
325-
msg = (
326-
"ERROR: For resource `%s` Found more than one resource with the same primary key `%s` and resource_module_params %s"
327-
% (
328-
self.resource_name,
329-
self.resource_id,
330-
self.resource_module_params,
326+
if self.resource_name in GETALL_ONLY_RESOURCES:
327+
for resources in existing_resource:
328+
# Check if all module params match this resource
329+
match_found = True
330+
for key, value in self.resource_module_params.items():
331+
if key in resources and resources[key] != value:
332+
match_found = False
333+
break
334+
335+
# If all parameters match, use this resource
336+
if match_found:
337+
self.existing_resource = resources
338+
break
339+
else:
340+
msg = (
341+
"ERROR: For resource `%s` Found more than one resource with the same primary key `%s` and resource_module_params %s"
342+
% (
343+
self.resource_name,
344+
self.resource_id,
345+
self.resource_module_params,
346+
)
331347
)
332-
)
333-
self.return_failure(msg)
334-
335-
self.existing_resource = existing_resource[0]
348+
self.return_failure(msg)
349+
else:
350+
self.existing_resource = existing_resource[0]
336351

337352
if self.resource_name in NITRO_ATTRIBUTES_ALIASES:
338353
self.existing_resource = self._add_nitro_attributes_aliases(

0 commit comments

Comments
 (0)