napalm-automation / napalm

Network Automation and Programmability Abstraction Layer with Multivendor support
Apache License 2.0
2.24k stars 552 forks source link

eos_fn0039_config optional_arg breaks multiline configuration #1485

Open tony-bonet opened 3 years ago

tony-bonet commented 3 years ago

Description of Issue/Question

While applying a multiline configuration, Eg: banner motd, while eos_fn0039_config=True an exception is thrown due to: eos/utils/cli_syntax.py if command.startswith(c):

In multiline case the command is a dict, not a string.

Note: Please check https://guides.github.com/features/mastering-markdown/ to see how to properly format your request.

Did you follow the steps from https://github.com/napalm-automation/napalm#faq

(Place an x between the square brackets where applicable)

Setup

napalm version

(Paste verbatim output from pip freeze | grep napalm between quotes below)

$  pip freeze | grep napalm
napalm==3.3.1
napalm-ansible==1.1.0

Network operating system version

(Paste verbatim output from show version - or equivalent - between quotes below)

# show version
Software image version: 4.21.3F-2GB

AND 

# show version
Software image version: 4.23.0F

Steps to Reproduce the Issue

Error Traceback

(Paste the complete traceback of the exception between quotes below)

>>> config = '''banner motd
... banner line 1
... banner line 2
... EOF
... '''

>>> dev.load_merge_candidate(config=config)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/eos.py", line 344, in load_merge_candidate
    self._load_config(filename, config, False)
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/eos.py", line 329, in _load_config
    self.device.run_commands(commands, fn0039_transform=self.fn0039_config)
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/pyeapi_syntax_wrapper.py", line 40, in run_commands
    commands = [cli_convert(cmd, self.cli_version) for cmd in commands]
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/pyeapi_syntax_wrapper.py", line 40, in <listcomp>
    commands = [cli_convert(cmd, self.cli_version) for cmd in commands]
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/utils/cli_syntax.py", line 359, in cli_convert
    return CONVERTER.convert(command, version)
  File "/opt/virtualenv/network_deployment/lib64/python3.6/site-packages/napalm/eos/utils/cli_syntax.py", line 343, in convert
    if command.startswith(c):
AttributeError: 'dict' object has no attribute 'startswith'

Proposed fix:

Check that command is a string before attempting conversion.

diff --git a/napalm/eos/utils/cli_syntax.py b/napalm/eos/utils/cli_syntax.py
index d4445fb..62f62df 100644
--- a/napalm/eos/utils/cli_syntax.py
+++ b/napalm/eos/utils/cli_syntax.py
@@ -340,8 +340,9 @@ class CliConverter:
             return command

         for c in self.syntax[version]:
-            if command.startswith(c):
-                return self.syntax[version][c] + command[len(c) :]
+            if isinstance(command, str):
+                if command.startswith(c):
+                    return self.syntax[version][c] + command[len(c) :]

         return command
mirceaulinic commented 3 years ago

Hi @tony-bonet. Thanks for reporting this. Your suggestion sounds good, feel free to open a PR and I shall merge and release soon! 👍🏼