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