Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for src plus match:exact (revive abandoned pull request) #1050

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions changelogs/fragments/1050-src-plus-match-exact.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- ios_config - Add support for src plus match:exact (https://github.com/ansible-collections/cisco.ios/issues/655).
105 changes: 85 additions & 20 deletions plugins/cliconf/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,29 +248,94 @@ def get_diff(
% (diff_replace, ", ".join(option_values["diff_replace"])),
)

# prepare candidate configuration
candidate_obj = NetworkConfig(indent=1)
want_src, want_banners = self._extract_banners(candidate)
candidate_obj.load(want_src)

if running and diff_match != "none":
# running configuration
have_src, have_banners = self._extract_banners(running)
running_obj = NetworkConfig(indent=1, contents=have_src, ignore_lines=diff_ignore_lines)
configdiffobjs = candidate_obj.difference(
running_obj,
path=path,
match=diff_match,
replace=diff_replace,
)
cand_pattern = r"(?P<parent>^\w.*\n?)(?P<child>(?:\s+.*\n?)*)"
# remove blank lines
candidate = re.sub("\n\n", "\n", candidate)
candidates = re.findall(cand_pattern, candidate, re.M)

diff["config_diff"] = ""
diff["banner_diff"] = {}

# exact plus src support. src can have multiple sections as candidates
# e.g policy-map foo, policy-map bar, policy-map baz etc.
if candidates and not path and diff_match == "exact":
for _candidate in candidates:
path = [_candidate[0].strip()]
_candidate = "".join(_candidate)
_candidate_obj = NetworkConfig(indent=1)
_candidate_obj.load(_candidate)

running_obj = NetworkConfig(
indent=1,
contents=running,
ignore_lines=diff_ignore_lines,
)

try:
have_lines = running_obj.get_block(path)
except ValueError:
have_lines = []
want_lines = _candidate_obj.get_block(path)

negates = ""
negated_parents = []
for line in have_lines:
if line not in want_lines:
negates += "".join(
f"{i}\n"
for i in line.parents
if i not in negates and i not in negated_parents
)

if line.has_children:
negated_parents.append(line.text)

if not any(i in negated_parents for i in line.parents):
negates += f"no {line}\n"

diff["config_diff"] += negates

wants = ""
for line in want_lines:
if line not in have_lines:
wants += "".join(f"{i}\n" for i in line.parents if i not in wants)
wants += f"{line}\n"

diff["config_diff"] += wants

diff["config_diff"] = diff["config_diff"].rstrip()
else:
configdiffobjs = candidate_obj.items
have_banners = {}
# The "original" code moved to this else-section
# prepare candidate configuration
candidate_obj = NetworkConfig(indent=1)
want_src, want_banners = self._extract_banners(candidate)
candidate_obj.load(want_src)

if running and diff_match != "none":
# running configuration
have_src, have_banners = self._extract_banners(running)

running_obj = NetworkConfig(
indent=1,
contents=have_src,
ignore_lines=diff_ignore_lines,
)

configdiffobjs = candidate_obj.difference(
running_obj,
path=path,
match=diff_match,
replace=diff_replace,
)

else:
configdiffobjs = candidate_obj.items
have_banners = {}

diff["config_diff"] = dumps(configdiffobjs, "commands") if configdiffobjs else ""
banners = self._diff_banners(want_banners, have_banners)
diff["banner_diff"] = banners if banners else {}

diff["config_diff"] = dumps(configdiffobjs, "commands") if configdiffobjs else ""
banners = self._diff_banners(want_banners, have_banners)
diff["banner_diff"] = banners if banners else {}
return diff

@enable_mode
Expand Down