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

Fix iosxr netconf plugin response namespace #49238

Merged
merged 3 commits into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 12 additions & 6 deletions lib/ansible/module_utils/network/iosxr/iosxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,10 @@ def get_config_diff(module, running=None, candidate=None):
def discard_config(module):
conn = get_connection(module)
try:
conn.discard_changes()
if is_netconf(module):
conn.discard_changes(remove_ns=True)
else:
conn.discard_changes()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

Expand All @@ -370,9 +373,9 @@ def commit_config(module, comment=None, confirmed=False, confirm_timeout=None,
try:
if is_netconf(module):
if check:
reply = conn.validate()
reply = conn.validate(remove_ns=True)
else:
reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist)
reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist, remove_ns=True)
elif is_cliconf(module):
if check:
module.fail_json(msg="Validate configuration is not supported with network_cli connection type")
Expand All @@ -389,7 +392,10 @@ def get_oper(module, filter=None):

if filter is not None:
try:
response = conn.get(filter)
if is_netconf(module):
response = conn.get(filter=filter, remove_ns=True)
else:
response = conn.get(filter)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
else:
Expand All @@ -404,7 +410,7 @@ def get_config(module, config_filter=None, source='running'):
# Note: Does not cache config in favour of latest config on every get operation.
try:
if is_netconf(module):
out = to_xml(conn.get_config(source=source, filter=config_filter))
out = to_xml(conn.get_config(source=source, filter=config_filter, remove_ns=True))
elif is_cliconf(module):
out = conn.get_config(source=source, flags=config_filter)
cfg = out.strip()
Expand Down Expand Up @@ -436,7 +442,7 @@ def load_config(module, command_filter, commit=False, replace=False,

try:
for filter in to_list(command_filter):
conn.edit_config(filter)
conn.edit_config(config=filter, remove_ns=True)

candidate = get_config(module, source='candidate', config_filter=nc_get_filter)
diff = get_config_diff(module, running, candidate)
Expand Down
62 changes: 43 additions & 19 deletions lib/ansible/plugins/netconf/iosxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,56 +125,80 @@ def guess_network_os(obj):

# TODO: change .xml to .data_xml, when ncclient supports data_xml on all platforms
@ensure_connected
def get(self, filter=None):
def get(self, filter=None, remove_ns=False):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure of history but why do we need remove_ns at first place ? is it for conversion to json ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc this logic was added to iosxr plugin so that parsing of XML response string using lxml library in the iosxr declarative modules is easier. If the namespace is present in the XML string the XPath traversal in declarative modules requires adding nested namespaces to traversal logic thus making it complex.

if isinstance(filter, list):
filter = tuple(filter)
try:
response = self.m.get(filter=filter)
return remove_namespaces(response)
resp = self.m.get(filter=filter)
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))

@ensure_connected
def get_config(self, source=None, filter=None):
def get_config(self, source=None, filter=None, remove_ns=False):
if isinstance(filter, list):
filter = tuple(filter)
try:
response = self.m.get_config(source=source, filter=filter)
return remove_namespaces(response)
resp = self.m.get_config(source=source, filter=filter)
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))

@ensure_connected
def edit_config(self, config=None, format='xml', target='candidate', default_operation=None, test_option=None, error_option=None):
def edit_config(self, config=None, format='xml', target='candidate', default_operation=None, test_option=None, error_option=None, remove_ns=False):
if config is None:
raise ValueError('config value must be provided')
try:
response = self.m.edit_config(config, format=format, target=target, default_operation=default_operation, test_option=test_option,
error_option=error_option)
return remove_namespaces(response)
resp = self.m.edit_config(config, format=format, target=target, default_operation=default_operation, test_option=test_option,
error_option=error_option)
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))

@ensure_connected
def commit(self, confirmed=False, timeout=None, persist=None):
def commit(self, confirmed=False, timeout=None, persist=None, remove_ns=False):
try:
response = self.m.commit(confirmed=confirmed, timeout=timeout, persist=persist)
return remove_namespaces(response)
resp = self.m.commit(confirmed=confirmed, timeout=timeout, persist=persist)
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))

@ensure_connected
def validate(self, source="candidate"):
def validate(self, source="candidate", remove_ns=False):
try:
response = self.m.validate(source=source)
return remove_namespaces(response)
resp = self.m.validate(source=source)
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))

@ensure_connected
def discard_changes(self):
def discard_changes(self, remove_ns=False):
try:
response = self.m.discard_changes()
return remove_namespaces(response)
resp = self.m.discard_changes()
if remove_ns:
response = remove_namespaces(resp)
else:
response = resp.data_xml if hasattr(resp, 'data_xml') else resp.xml
return response
except RPCError as exc:
raise Exception(to_xml(exc.xml))