resource_list_compare filter plugin added (#89)
resource_list_compare filter plugin added Signed-off-by: Rohit Thakur rohitthakur2590@outlook.com SUMMARY resolves: #88 Test Coverage plugins/filter/param_list_compare.py 95% tests/unit/plugins/filter/test_param_list_compare.py 100% ISSUE TYPE Feature Pull Request COMPONENT NAME ADDITIONAL INFORMATION Reviewed-by: Ganesh Nalawade <None> Reviewed-by: Bradley A. Thornton <bthornto@redhat.com> Reviewed-by: Rohit Thakur <rohitthakur2590@outlook.com> Reviewed-by: None <None>pull/91/head
parent
61a826c997
commit
2f071599d0
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- Add new plugin param_list_compare that generates the final param list after comparing base and provided/target param list.
|
|
@ -0,0 +1,195 @@
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
name: param_list_compare
|
||||||
|
author: Rohit Thakur (@rohitthakur2590)
|
||||||
|
version_added: "2.4.0"
|
||||||
|
short_description: Generate the final param list combining/comparing base and provided parameters.
|
||||||
|
description:
|
||||||
|
- Generate the final list of parameters after comparing with base list and provided/target list of params/bangs.
|
||||||
|
options:
|
||||||
|
base:
|
||||||
|
description: Specify the base list.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
target:
|
||||||
|
description: Specify the target list.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = r"""
|
||||||
|
- set_fact:
|
||||||
|
base: ['1','2','3','4','5']
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
target: ['!all','2','4']
|
||||||
|
|
||||||
|
- name: Get final list of parameters
|
||||||
|
register: result
|
||||||
|
set_fact:
|
||||||
|
final_params: "{{ base|param_list_compare(target) }}"
|
||||||
|
|
||||||
|
# TASK [Target list] **********************************************************
|
||||||
|
# ok: [localhost] => {
|
||||||
|
# "msg": {
|
||||||
|
# "actionable": [
|
||||||
|
# "2",
|
||||||
|
# "4"
|
||||||
|
# ],
|
||||||
|
# "unsupported": []
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Network Specific Example
|
||||||
|
# -----------
|
||||||
|
- set_fact:
|
||||||
|
ios_resources:
|
||||||
|
- "acl_interfaces"
|
||||||
|
- "acls"
|
||||||
|
- "bgp_address_family"
|
||||||
|
- "bgp_global"
|
||||||
|
- "interfaces"
|
||||||
|
- "l2_interfaces"
|
||||||
|
- "l3_interfaces"
|
||||||
|
- "lacp"
|
||||||
|
- "lacp_interfaces"
|
||||||
|
- "lag_interfaces"
|
||||||
|
- "lldp_global"
|
||||||
|
- "lldp_interfaces"
|
||||||
|
- "logging_global"
|
||||||
|
- "ospf_interfaces"
|
||||||
|
- "ospfv2"
|
||||||
|
- "ospfv3"
|
||||||
|
- "prefix_lists"
|
||||||
|
- "route_maps"
|
||||||
|
- "static_routes"
|
||||||
|
- "vlans"
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
target_resources:
|
||||||
|
- '!all'
|
||||||
|
- 'vlan'
|
||||||
|
- 'bgp_global'
|
||||||
|
|
||||||
|
- name: Get final list of target resources/params
|
||||||
|
register: result
|
||||||
|
set_fact:
|
||||||
|
network_resources: "{{ ios_resources|param_list_compare(target_resources) }}"
|
||||||
|
|
||||||
|
- name: Target list of network resources
|
||||||
|
debug:
|
||||||
|
msg: "{{ network_resources }}"
|
||||||
|
|
||||||
|
# TASK [Target list of network resources] *******************************************************************************************************************
|
||||||
|
# ok: [localhost] => {
|
||||||
|
# "msg": {
|
||||||
|
# "actionable": [
|
||||||
|
# "bgp_global",
|
||||||
|
# "vlans"
|
||||||
|
# ],
|
||||||
|
# "unsupported": []
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
- name: Get final list of target resources/params
|
||||||
|
register: result
|
||||||
|
set_fact:
|
||||||
|
network_resources: "{{ ios_resources|param_list_compare(target=['vla', 'ntp_global', 'logging_global']) }}"
|
||||||
|
|
||||||
|
- name: Target list of network resources
|
||||||
|
debug:
|
||||||
|
msg: "{{ network_resources }}"
|
||||||
|
|
||||||
|
# TASK [Target list of network resources] ************************************************
|
||||||
|
# ok: [localhost] => {
|
||||||
|
# "msg": {
|
||||||
|
# "actionable": [
|
||||||
|
# "logging_global"
|
||||||
|
# ],
|
||||||
|
# "unsupported": [
|
||||||
|
# "vla",
|
||||||
|
# "ntp_global"
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
actionable:
|
||||||
|
description: list of combined params
|
||||||
|
type: list
|
||||||
|
|
||||||
|
unsupported:
|
||||||
|
description: list of unsupported params
|
||||||
|
type: list
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
|
||||||
|
check_argspec,
|
||||||
|
)
|
||||||
|
|
||||||
|
ARGSPEC_CONDITIONALS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def param_list_compare(*args, **kwargs):
|
||||||
|
params = ["base", "target"]
|
||||||
|
data = dict(zip(params, args))
|
||||||
|
data.update(kwargs)
|
||||||
|
|
||||||
|
if len(data) < 2:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
"Missing either 'base' or 'other value in filter input,"
|
||||||
|
"refer 'ansible.utils.param_list_compare' filter plugin documentation for details"
|
||||||
|
)
|
||||||
|
|
||||||
|
valid, argspec_result, updated_params = check_argspec(
|
||||||
|
DOCUMENTATION,
|
||||||
|
"param_list_compare filter",
|
||||||
|
schema_conditionals=ARGSPEC_CONDITIONALS,
|
||||||
|
**data
|
||||||
|
)
|
||||||
|
if not valid:
|
||||||
|
raise AnsibleFilterError(
|
||||||
|
"{argspec_result} with errors: {argspec_errors}".format(
|
||||||
|
argspec_result=argspec_result.get("msg"),
|
||||||
|
argspec_errors=argspec_result.get("errors"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
base = data["base"]
|
||||||
|
other = data["target"]
|
||||||
|
combined = []
|
||||||
|
alls = [x for x in other if x == "all"]
|
||||||
|
bangs = [x[1:] for x in other if x.startswith("!")]
|
||||||
|
rbangs = [x for x in other if x.startswith("!")]
|
||||||
|
remain = [
|
||||||
|
x for x in other if x not in alls and x not in rbangs and x in base
|
||||||
|
]
|
||||||
|
unsupported = [
|
||||||
|
x for x in other if x not in alls and x not in rbangs and x not in base
|
||||||
|
]
|
||||||
|
|
||||||
|
if alls:
|
||||||
|
combined = base
|
||||||
|
for entry in bangs:
|
||||||
|
if entry in combined:
|
||||||
|
combined.remove(entry)
|
||||||
|
for entry in remain:
|
||||||
|
if entry not in combined:
|
||||||
|
combined.append(entry)
|
||||||
|
combined.sort()
|
||||||
|
output = {"actionable": combined, "unsupported": unsupported}
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
class FilterModule(object):
|
||||||
|
""" param_list_compare """
|
||||||
|
|
||||||
|
def filters(self):
|
||||||
|
"""a mapping of filter names to functions"""
|
||||||
|
return {"param_list_compare": param_list_compare}
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
- debug:
|
||||||
|
msg: "START param_list_compare integration tests on connection={{ ansible_connection }}"
|
||||||
|
|
||||||
|
- name: Setup supported resource module list json
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
network_resources:
|
||||||
|
modules:
|
||||||
|
- 'acl_interfaces'
|
||||||
|
- 'acls'
|
||||||
|
- 'bgp_address_family'
|
||||||
|
- 'bgp_global'
|
||||||
|
- 'interfaces'
|
||||||
|
- 'l2_interfaces'
|
||||||
|
- 'l3_interfaces'
|
||||||
|
- 'lacp'
|
||||||
|
- 'lacp_interfaces'
|
||||||
|
- 'lag_interfaces'
|
||||||
|
- 'lldp_global'
|
||||||
|
- 'lldp_interfaces'
|
||||||
|
- 'logging_global'
|
||||||
|
- 'ospf_interfaces'
|
||||||
|
- 'ospfv2'
|
||||||
|
- 'ospfv3'
|
||||||
|
- 'prefix_lists'
|
||||||
|
- 'route_maps'
|
||||||
|
- 'static_routes'
|
||||||
|
- 'vlans'
|
||||||
|
|
||||||
|
- name: Setup target resources with bangs
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
provided_resources:
|
||||||
|
- '!all'
|
||||||
|
- '!acl_interfaces'
|
||||||
|
- 'acls'
|
||||||
|
- 'bgp_address_family'
|
||||||
|
- 'bgp_global'
|
||||||
|
|
||||||
|
- name: Setup target resources with bangs
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
expected_network_resources:
|
||||||
|
- 'acls'
|
||||||
|
- 'bgp_address_family'
|
||||||
|
- 'bgp_global'
|
||||||
|
|
||||||
|
- name: Get the final list of resources
|
||||||
|
set_fact:
|
||||||
|
final_network_resources: "{{ network_resources['modules']|ansible.utils.param_list_compare(provided_resources) }}"
|
||||||
|
|
||||||
|
- name: Assert final network resources
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ expected_network_resources | symmetric_difference(final_network_resources['actionable']) |length\
|
||||||
|
\ == 0 }}"
|
||||||
|
- debug:
|
||||||
|
msg: "END param_list_compare integration tests on connection={{ ansible_connection }}"
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
- name: Recursively find all test files
|
||||||
|
find:
|
||||||
|
file_type: file
|
||||||
|
paths: "{{ role_path }}/tasks/include"
|
||||||
|
recurse: true
|
||||||
|
use_regex: true
|
||||||
|
patterns:
|
||||||
|
- '^(?!_).+$'
|
||||||
|
register: found
|
||||||
|
|
||||||
|
- include: "{{ item.path }}"
|
||||||
|
loop: "{{ found.files }}"
|
|
@ -0,0 +1,93 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2021 Red Hat
|
||||||
|
# GNU General Public License v3.0+
|
||||||
|
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from ansible.errors import AnsibleFilterError
|
||||||
|
from ansible_collections.ansible.utils.plugins.filter.param_list_compare import (
|
||||||
|
param_list_compare,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestParam_list_compare_merge(unittest.TestCase):
|
||||||
|
def test_valid_data(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = ["interfaces", "l2_interfaces", "l3_interfaces"]
|
||||||
|
other = ["all"]
|
||||||
|
args = [base, other]
|
||||||
|
kwargs = {}
|
||||||
|
result = param_list_compare(*args, **kwargs)
|
||||||
|
self.assertEqual(result["actionable"], base)
|
||||||
|
|
||||||
|
def test_valid_data_same_contents(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = ["interfaces", "l2_interfaces", "l3_interfaces"]
|
||||||
|
other = ["interfaces", "l2_interfaces", "l3_interfaces"]
|
||||||
|
args = [base, other]
|
||||||
|
kwargs = {}
|
||||||
|
result = param_list_compare(*args, **kwargs)
|
||||||
|
self.assertEqual(result["actionable"], base)
|
||||||
|
|
||||||
|
def test_valid_data_with_not_bang(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = ["interfaces", "l2_interfaces", "l3_interfaces"]
|
||||||
|
other = ["!l2_interfaces", "all"]
|
||||||
|
args = [base, other]
|
||||||
|
expected = ["interfaces", "l3_interfaces"]
|
||||||
|
kwargs = {}
|
||||||
|
result = param_list_compare(*args, **kwargs)
|
||||||
|
self.assertEqual(result["actionable"], expected)
|
||||||
|
|
||||||
|
def test_invalid_args_length_data(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = {}
|
||||||
|
args = [base]
|
||||||
|
kwargs = {}
|
||||||
|
with self.assertRaises(AnsibleFilterError) as error:
|
||||||
|
param_list_compare(*args, **kwargs)
|
||||||
|
self.assertIn(
|
||||||
|
"Missing either 'base' or 'other value in filter input",
|
||||||
|
str(error.exception),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_invalid_base_type_data(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = {}
|
||||||
|
other = ["all"]
|
||||||
|
args = [base, other]
|
||||||
|
kwargs = {}
|
||||||
|
with self.assertRaises(AnsibleFilterError) as error:
|
||||||
|
param_list_compare(*args, **kwargs)
|
||||||
|
self.assertIn("cannot be converted to a list", str(error.exception))
|
||||||
|
|
||||||
|
def test_invalid_other_type_data(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = ["interfaces"]
|
||||||
|
other = {"all": None}
|
||||||
|
args = [base, other]
|
||||||
|
kwargs = {}
|
||||||
|
with self.assertRaises(AnsibleFilterError) as error:
|
||||||
|
param_list_compare(*args, **kwargs)
|
||||||
|
self.assertIn("cannot be converted to a list", str(error.exception))
|
||||||
|
|
||||||
|
def test_invalid_unsupported_bang(self):
|
||||||
|
"""Check passing valid data as per criteria"""
|
||||||
|
|
||||||
|
base = ["interfaces"]
|
||||||
|
other = ["every"]
|
||||||
|
args = [base, other]
|
||||||
|
kwargs = {}
|
||||||
|
result = param_list_compare(*args, **kwargs)
|
||||||
|
self.assertEqual(result["unsupported"], other)
|
Loading…
Reference in New Issue