Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 59 additions & 16 deletions plugins/module_utils/nsxt_base_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native

import collections

import sys
if sys.version_info[0] < 3:
raise Exception("Must be using Python 3")
Expand Down Expand Up @@ -257,6 +259,18 @@ def update_resource_params(self, nsx_resource_params):
# Should be overridden in the subclass if needed
pass

def convert_to_ordered_data(self, data):
if isinstance(data, list):
data = sorted([self.convert_to_ordered_data(d) for d in data],
key=str)
elif isinstance(data, dict):
# sort dict with keys
data = collections.OrderedDict(
sorted(data.items(), key=lambda d: d[0]))
for key in data:
data[key] = self.convert_to_ordered_data(data[key])
return data

def check_for_update(self, existing_params, resource_params):
"""
resource_params: dict
Expand All @@ -274,22 +288,23 @@ def check_for_update(self, existing_params, resource_params):
for k, v in resource_params.items():
if k not in existing_params:
return True
elif type(v).__name__ == 'dict':
elif isinstance(v, collections.OrderedDict):
if self.check_for_update(existing_params[k], v):
return True
elif v != existing_params[k]:
def compare_lists(list1, list2):
def do_lists_differ(list1, list2):
# Returns True if list1 and list2 differ
try:
# If the lists can be converted into sets, do so and
# compare lists as sets.
set1 = set(list1)
set2 = set(list2)
return set1 != set2
except Exception:
if len(list1) != len(list2):
return True
if type(v).__name__ == 'list':
if compare_lists(v, existing_params[k]):
for e1, e2 in zip(list1, list2):
if isinstance(e1, collections.OrderedDict):
return self.check_for_update(e1, e2)
elif isinstance(e1, list):
return do_lists_differ(e1, e2)
else:
return e1 != e2
if isinstance(v, list):
if do_lists_differ(existing_params[k], v):
return True
continue
return True
Expand Down Expand Up @@ -549,19 +564,47 @@ def _get_base_arg_spec_of_resource(self):
def _extract_nsx_resource_params(self, resource_params):
# extract the params belonging to this resource only.
filtered_params = {}

def filter_with_spec(spec):
def filter_with_spec(spec, filtered_params, resource_params):
for key in spec.keys():
if (key in resource_params and
resource_params[key] is not None):
filtered_params[key] = resource_params[key]
v = resource_params[key]
current_spec = spec[key]
current_spec_type = current_spec.get("type")
if current_spec_type == 'dict':
params = filter_with_spec(
current_spec, {}, v)
if params:
filtered_params[key] = params
elif current_spec_type == 'list' and v:
if current_spec.get("elements") == "dict":
all_params = []
for element in v:
params = filter_with_spec(
current_spec['options'], {}, element)
if params:
all_params.append(params)
if all_params:
filtered_params[key] = all_params
else:
filtered_params[key] = v
else:
filtered_params[key] = v
return filtered_params

filter_with_spec(self.get_resource_spec())
filter_with_spec(self._get_base_arg_spec_of_nsx_resource())
filtered_params = filter_with_spec(
self.get_resource_spec(), filtered_params, resource_params)
filtered_params = filter_with_spec(
self._get_base_arg_spec_of_nsx_resource(), filtered_params,
resource_params)
return filtered_params

def _achieve_present_state(self, successful_resource_exec_logs):
self.update_resource_params(self.nsx_resource_params)
self.nsx_resource_params = self.convert_to_ordered_data(
self.nsx_resource_params)
self.existing_resource = self.convert_to_ordered_data(
self.existing_resource)
is_resource_updated = self.check_for_update(
self.existing_resource, self.nsx_resource_params)
if not is_resource_updated:
Expand Down
16 changes: 16 additions & 0 deletions plugins/modules/nsxt_policy_tier0.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,16 @@
IPSec VPN local-endpoint subnets
advertised by TIER1.
type: list
destinations:
description:
- List of destinations for a given
redistribution rule
- Each rule can have more than one
destination. If destinations not
specified for a given rule, default
destination will be BGP
default: ["BGP"]
choices: ["BGP", "OSPF"]
ha_vip_configs:
type: list
elements: dict
Expand Down Expand Up @@ -1690,6 +1700,12 @@ def get_resource_spec():
elements='str',
required=False
),
destinations=dict(
type='list',
elements='str',
required=False,
default=["BGP"],
),
)
)
)
Expand Down
16 changes: 16 additions & 0 deletions plugins/modules/nsxt_policy_tier1.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,16 @@
IPSec VPN local-endpoint subnets
advertised by TIER1.
type: list
destinations:
description:
- List of destinations for a given
redistribution rule
- Each rule can have more than one
destination. If destinations not
specified for a given rule, default
destination will be BGP
default: ["BGP"]
choices: ["BGP", "OSPF"]
ha_vip_configs:
type: list
elements: dict
Expand Down Expand Up @@ -1130,6 +1140,12 @@ def get_resource_spec():
elements='str',
required=False
),
destinations=dict(
type='list',
elements='str',
required=False,
default=["BGP"],
),
)
)
)
Expand Down
75 changes: 73 additions & 2 deletions tests/unit/plugins/module_utils/test_nsxt_base_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import collections

import unittest
import json
Expand Down Expand Up @@ -624,6 +625,24 @@ def test_detached_delete_child():

nsxt_base_resource.BASE_RESOURCES = init_base_resources

def test_convert_to_ordered_data(self):
simple_dummy_resource = SimpleDummyNSXTResource()
resource_params = {"dummy": ["dummy2", "dummy1"]}
observed = simple_dummy_resource.convert_to_ordered_data(
resource_params)
expected = collections.OrderedDict({"dummy": ["dummy1", "dummy2"]})
self.assertEqual(observed, expected)

resource_params = {"dummy2": {"dummy1": "dummy", "dummy2": "dummy"},
"dummy1": {"dummy4": "dummy", "dummy2": "dummy"}}
observed = simple_dummy_resource.convert_to_ordered_data(
resource_params)
expected = collections.OrderedDict(
{"dummy1": collections.OrderedDict(
{"dummy2": "dummy", "dummy4": "dummy"}),
"dummy2": {"dummy1": "dummy", "dummy2": "dummy"}})
self.assertEqual(observed, expected)

def test_check_for_update(self):
simple_dummy_resource = SimpleDummyNSXTResource()

Expand All @@ -634,85 +653,137 @@ def test_with_no_existing_resource():
def test_with_same_params():
existing_params = {"dummy": "dummy"}
resource_params = {"dummy": "dummy"}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertFalse(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_diff_params_simple():
existing_params = {"dummy": "dummy"}
resource_params = {"dummy1": "dummy"}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_same_params_list_same_order():
existing_params = {"dummy": ["dummy1", "dummy2"]}
resource_params = {"dummy": ["dummy1", "dummy2"]}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertFalse(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_same_params_list_different_order():
existing_params = {"dummy": ["dummy1", "dummy2"]}
resource_params = {"dummy": ["dummy2", "dummy1"]}
existing_params = {"dummy": ["dummy1", "dummy2", "dummy3"]}
resource_params = {"dummy": ["dummy2", "dummy1", "dummy3"]}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertFalse(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_same_params_single_dict():
existing_params = {"dummy": {"dummy": "dummy"}}
resource_params = {"dummy": {"dummy": "dummy"}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertFalse(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_diff_params_single_dict():
existing_params = {"dummy": {"dummy": "dummy"}}
resource_params = {"dummy": {"dummy1": "dummy"}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

existing_params = {"dummy": {"dummy": "dummy"}}
resource_params = {"dummy": {"dummy": "dummy1"}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

existing_params = {"dummy": {"dummy": "dummy"}}
resource_params = {"dummy1": {"dummy": "dummy"}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_same_params_multilevel_dict():
existing_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
resource_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertFalse(simple_dummy_resource.check_for_update(
existing_params, resource_params))

def test_with_diff_params_multilevel_dict():
existing_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
resource_params = {"dummy1": {"dummy": {"dummy": "dummy"}}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

existing_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
resource_params = {"dummy": {"dummy1": {"dummy": "dummy"}}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

existing_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
resource_params = {"dummy": {"dummy": {"dummy1": "dummy"}}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))

existing_params = {"dummy": {"dummy": {"dummy": "dummy"}}}
resource_params = {"dummy": {"dummy": {"dummy": "dummy1"}}}
existing_params = simple_dummy_resource.convert_to_ordered_data(
existing_params)
resource_params = simple_dummy_resource.convert_to_ordered_data(
resource_params)

self.assertTrue(simple_dummy_resource.check_for_update(
existing_params, resource_params))
Expand Down