Skip to content

Commit 15c0ac9

Browse files
Fix boolean values in bgprouter example
1 parent 8f43fcb commit 15c0ac9

File tree

8 files changed

+112
-50
lines changed

8 files changed

+112
-50
lines changed

examples/bgpRouter.yaml renamed to examples/bgprouter.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
tasks:
66
- name: Configure BGP routing
77
delegate_to: localhost
8-
netscaler.adc.bgpRouter:
8+
netscaler.adc.bgprouter:
99
state: present
10-
localAS: 10
10+
localAS: 122
1111
afParams.addressFamily: "ipv4"
1212
afParams.redistribute.protocol: "kernel"
1313
routerId: "10.102.201.219"

meta/runtime.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ action_groups:
697697
- route
698698
- route6
699699
- routerdynamicrouting
700-
- bgpRouter
700+
- bgprouter
701701
- rsskeytype
702702
- save_config
703703
- server

plugins/module_utils/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .constants import (
1919
HTTP_SUCCESS_CODES,
2020
NESTED_POST_DATA_RESOURCES,
21+
NESTED_POST_DATA_RESOURCES_ALIAS,
2122
)
2223
from .decorators import trace
2324
from .logger import log
@@ -107,7 +108,7 @@ def url_builder(
107108
self._module.params["nsip"],
108109
self.api_path,
109110
"routerDynamicRouting",
110-
resource,
111+
NESTED_POST_DATA_RESOURCES_ALIAS[resource],
111112
)
112113
else:
113114
url = "%s://%s/%s/%s" % (

plugins/module_utils/common.py

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
HTTP_RESOURCE_NOT_FOUND,
1515
HTTP_SUCCESS_CODES,
1616
NESTED_POST_DATA_RESOURCES,
17-
GLOBAL_BINDING_ARG_LIST
17+
GLOBAL_BINDING_ARG_LIST,
18+
NESTED_POST_DATA_RESOURCES_ALIAS,
1819
)
1920
from .decorators import trace
2021
from .logger import log
@@ -96,7 +97,7 @@ def get_resource(client, resource_name, resource_id=None, resource_module_params
9697
else:
9798
if resource_name in NESTED_POST_DATA_RESOURCES:
9899
status_code, response_body = client.get(
99-
resource="routerDynamicRouting/%s" % resource_name,
100+
resource="routerDynamicRouting/%s" % NESTED_POST_DATA_RESOURCES_ALIAS[resource_name],
100101
id=resource_id,
101102
args=get_args,
102103
)
@@ -108,12 +109,15 @@ def get_resource(client, resource_name, resource_id=None, resource_module_params
108109
)
109110
if status_code in {HTTP_RESOURCE_NOT_FOUND}:
110111
return False, []
112+
return_response = None
111113
if status_code in HTTP_SUCCESS_CODES:
112114
# for zero bindings and some resources, the response_body will be {'errorcode': 0, 'message': 'Done', 'severity': 'NONE'}
113115
if resource_name in NESTED_POST_DATA_RESOURCES:
114116
if "routerDynamicRouting" in response_body:
115-
response_body = response_body["routerDynamicRouting"]
116-
if resource_name not in response_body:
117+
return_response = response_body["routerDynamicRouting"][NESTED_POST_DATA_RESOURCES_ALIAS[resource_name]]
118+
else:
119+
return False, []
120+
elif resource_name not in response_body:
117121
if resource_name == "sslcipher":
118122
resource_primary_key = NITRO_RESOURCE_MAP[resource_name]["primary_key"]
119123
return True, [
@@ -122,32 +126,33 @@ def get_resource(client, resource_name, resource_id=None, resource_module_params
122126

123127
return False, []
124128

125-
# `update-only` resources return a dict instead of a list.
126-
return_response = response_body[resource_name]
129+
# `update-only` resources return a dict instead of a list.
130+
if resource_name not in NESTED_POST_DATA_RESOURCES:
131+
return_response = response_body[resource_name]
127132
# FIXME: NITRO-BUG: for some resources like `policypatset_pattern_binding`, NITRO returns keys with uppercase. eg: `String` for `string`.
128133
# So, we are converting the keys to lowercase.
129134
# except for `ping` and `traceroute`, all the othe resources returns a keys with lowercase.
130135
# These `ping` and `traceroute` do not have GET operation. So, we are not handling them here.
131-
if isinstance(return_response, dict):
132-
return_response = [{k.lower(): v for k, v in return_response.items()}]
133-
elif isinstance(return_response, list):
134-
return_response = [
135-
{k.lower(): v for k, v in resource.items()}
136-
for resource in return_response
137-
]
138-
else:
139-
log(
140-
"WARNING: Unexpected response for resource `{}`. Expected a list or a dict, but got: {}".format(
141-
resource_name, return_response
136+
if resource_name not in NESTED_POST_DATA_RESOURCES:
137+
if isinstance(return_response, dict):
138+
return_response = [{k.lower(): v for k, v in return_response.items()}]
139+
elif isinstance(return_response, list):
140+
return_response = [
141+
{k.lower(): v for k, v in resource.items()}
142+
for resource in return_response
143+
]
144+
else:
145+
log(
146+
"WARNING: Unexpected response for resource `{}`. Expected a list or a dict, but got: {}".format(
147+
resource_name, return_response
148+
)
142149
)
143-
)
144150

145151
# Take care of NITRO Anomolies
146152
return_response = fix_nitro_anomolies(
147153
resource_name, resource_module_params, return_response
148154
)
149155
return (True, return_response)
150-
log("pass 3 ")
151156
return False, []
152157

153158

@@ -233,26 +238,27 @@ def _check_create_resource_params(resource_name, resource_module_params, action=
233238
else:
234239
# TODO: Should we allow non-add keys for the resource? OR should we error out if any non-add key is passed?
235240
if resource_name in NESTED_POST_DATA_RESOURCES:
236-
post_data = {"routerDynamicRouting": {resource_name: {}}}
237-
resource_add_keys = NITRO_RESOURCE_MAP[resource_name]["add_payload_keys"]
238-
239-
for key in resource_module_params.keys():
240-
if key in resource_add_keys:
241-
keylist = key.split(".")
242-
current_dict = post_data["routerDynamicRouting"][resource_name]
243-
for i, k in enumerate(keylist):
244-
if i == len(keylist) - 1:
245-
current_dict[k] = resource_module_params[key]
246-
else:
247-
if k not in current_dict:
248-
current_dict[k] = {}
249-
current_dict = current_dict[k]
250-
else:
251-
log(
252-
"WARNING: Key `{}` is not allowed for the resource `{}` for CREATE operation. Skipping the key for the operation".format(
253-
key, resource_name
254-
)
241+
resource_add_keys = NITRO_RESOURCE_MAP[resource_name]["add_payload_keys"]
242+
resource_name = NESTED_POST_DATA_RESOURCES_ALIAS[resource_name]
243+
post_data = {"routerDynamicRouting": {resource_name: {}}}
244+
245+
for key in resource_module_params.keys():
246+
if key in resource_add_keys:
247+
keylist = key.split(".")
248+
current_dict = post_data["routerDynamicRouting"][resource_name]
249+
for i, k in enumerate(keylist):
250+
if i == len(keylist) - 1:
251+
current_dict[k] = resource_module_params[key]
252+
else:
253+
if k not in current_dict:
254+
current_dict[k] = {}
255+
current_dict = current_dict[k]
256+
else:
257+
log(
258+
"WARNING: Key `{}` is not allowed for the resource `{}` for CREATE operation. Skipping the key for the operation".format(
259+
key, resource_name
255260
)
261+
)
256262
else:
257263
for key in resource_module_params.keys():
258264
if not action:

plugins/module_utils/constants.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
"sslcertkey": {"password"},
2727
}
2828

29-
NESTED_POST_DATA_RESOURCES = ["bgpRouter"]
29+
NESTED_POST_DATA_RESOURCES = ["bgprouter"]
30+
31+
NESTED_POST_DATA_RESOURCES_ALIAS = {
32+
"bgprouter": "bgpRouter",
33+
}
3034

3135
# NITRO accepts some attributes with a name and responsds with a different name in its GET reponse.
3236
# Eg: For "gslbservice" resource, NITRO expects "ip" in POST request

plugins/module_utils/module_executor.py

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
NITRO_ATTRIBUTES_ALIASES,
4141
NESTED_POST_DATA_RESOURCES,
4242
GETALL_ONLY_RESOURCES,
43+
NESTED_POST_DATA_RESOURCES_ALIAS,
4344
)
4445
from .decorators import trace
4546
from .logger import log, loglines
@@ -148,7 +149,10 @@ def __init__(self, resource_name, supports_check_mode=True):
148149
}:
149150
self.module.params["api_path"] = "nitro/v2/config"
150151
self.have_token = self.module.params.get("nitro_auth_token", None)
151-
self.client = NitroAPIClient(self.module, self.resource_name)
152+
if self.resource_name in NESTED_POST_DATA_RESOURCES:
153+
self.client = NitroAPIClient(self.module, NESTED_POST_DATA_RESOURCES_ALIAS[self.resource_name])
154+
else:
155+
self.client = NitroAPIClient(self.module, self.resource_name)
152156
have_userpass = all([
153157
self.module.params.get("nitro_user"),
154158
self.module.params.get("nitro_pass")
@@ -385,7 +389,45 @@ def is_attribute_equal(
385389
)
386390
# By default, compare as string values
387391
return str(existing_attribute_value) == str(module_params_attribute_value)
392+
@trace
393+
def is_resource_identical_nested(self):
394+
diff_list = []
395+
396+
def get_nested_value(data, path):
397+
cur = data
398+
for p in path.split('.'):
399+
if isinstance(cur, dict) and p in cur:
400+
cur = cur[p]
401+
else:
402+
return None
403+
return cur
404+
405+
for key, desired_value in self.resource_module_params.items():
406+
existing_value = get_nested_value(self.existing_resource, key)
388407

408+
if not self.is_attribute_equal(key, existing_value, desired_value):
409+
str_tuple = (
410+
key,
411+
type(existing_value),
412+
existing_value,
413+
type(desired_value),
414+
desired_value,
415+
)
416+
msg_str = (
417+
"Attribute `%s` differs. Desired: (%s) %s. Existing: (%s) %s"
418+
% str_tuple
419+
)
420+
diff_list.append(msg_str)
421+
log(msg_str)
422+
423+
if diff_list:
424+
self.module_result["diff_list"] = diff_list
425+
return False
426+
else:
427+
self.module_result.pop("diff_list", None)
428+
return True
429+
430+
389431
@trace
390432
def is_resource_identical(self):
391433
"""
@@ -465,7 +507,7 @@ def create_or_update(self):
465507

466508
self.module_result["changed"] = True
467509
log(
468-
"INFO: Resource %s:%s does not exist. Will be CREATED."
510+
"INFO: Resource 111 %s:%s does not exist. Will be CREATED."
469511
% (
470512
self.resource_name,
471513
self.resource_id,
@@ -524,8 +566,14 @@ def create_or_update(self):
524566
# it will remove them from the module_params and update the resource
525567
# 2. Second iteration will check if the resource is identical. If not, it will update the resource after ignoring the
526568
# non-updatable resources
527-
is_identical, immutable_keys_list = self.is_resource_identical()
569+
if self.resource_name in NESTED_POST_DATA_RESOURCES:
570+
is_identical = self.is_resource_identical_nested()
571+
immutable_keys_list = None
572+
else:
573+
is_identical, immutable_keys_list = self.is_resource_identical()
574+
log(f"is_identical: {is_identical}")
528575
if is_identical:
576+
log("i am here")
529577
log(
530578
"INFO: Resource `%s:%s` exists and is identical. No change required."
531579
% (
@@ -585,8 +633,10 @@ def create_or_update(self):
585633
# in case user wants to remove non-updatable params, we will remove them from the module_params
586634
for key in immutable_keys_list:
587635
self.resource_module_params.pop(key)
588-
589-
is_identical, temp_immutable_list = self.is_resource_identical()
636+
if self.resource_name in NESTED_POST_DATA_RESOURCES:
637+
is_identical = self.is_resource_identical_nested()
638+
else:
639+
is_identical, temp_immutable_list = self.is_resource_identical()
590640
# temp_immutable_list is a dummy as '_' is not allowed in lint.
591641
if is_identical:
592642
msg = (
@@ -752,6 +802,7 @@ def update_bindings(
752802
)
753803

754804
else:
805+
log("i am here 222")
755806
log(
756807
"INFO: Resource %s:%s's binding %s:%s exists and is identical. No change required."
757808
% (

plugins/module_utils/nitro_resource_map.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16532,8 +16532,8 @@
1653216532
"singleton": False,
1653316533
"update_payload_keys": [],
1653416534
},
16535-
"bgpRouter": {
16536-
"_supported_operations": ["add", "delete", "get"],
16535+
"bgprouter": {
16536+
"_supported_operations": ["add", "delete", "get", "unset"],
1653716537
"action_payload_keys": {
1653816538
"create": [],
1653916539
"force": [],
File renamed without changes.

0 commit comments

Comments
 (0)