Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/803.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed an issue where an empty config would raise an error when parsing Palo Alto Networks PanOS.
6 changes: 4 additions & 2 deletions netutils/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1553,12 +1553,14 @@ def build_config_relationship(self) -> t.List[ConfigLine]: # pylint: disable=to
True
"""
if self.config_lines_only is None:
raise ValueError("Config is empty.")
return []
config_lines = self.config_lines_only.splitlines()
if not config_lines:
return []

if "@dirtyId" in self.config_lines_only:
# We have to specifically check for JSON format because it can be confused with the brace format
raise ValueError("Found 'json' configuration format. Please provide in 'set' or 'default' (brace) format.")
config_lines = self.config_lines_only.splitlines()
if any(line.endswith("{") for line in config_lines):
converted_config = paloalto_panos_brace_to_set(cfg=self.config, cfg_type="string")
list_config = converted_config.splitlines()
Expand Down
31 changes: 20 additions & 11 deletions tests/unit/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@
base_parameters = []
find_all_children_parameters = []
find_children_w_parents_parameters = []
for network_os in list(compliance.parser_map.keys()):
for _file in glob.glob(f"{MOCK_DIR}/base/{network_os}/*{TXT_FILE}"):
base_parameters.append([_file, network_os])
for _file in glob.glob(f"{MOCK_DIR}/find_all_children/{network_os}/*{TXT_FILE}"):
find_all_children_parameters.append([_file, network_os])
for _file in glob.glob(f"{MOCK_DIR}/find_children_w_parents/{network_os}/*{TXT_FILE}"):
find_children_w_parents_parameters.append([_file, network_os])
all_network_os = list(compliance.parser_map.keys())
for _network_os in all_network_os:
for _file in glob.glob(f"{MOCK_DIR}/base/{_network_os}/*{TXT_FILE}"):
base_parameters.append([_file, _network_os])
for _file in glob.glob(f"{MOCK_DIR}/find_all_children/{_network_os}/*{TXT_FILE}"):
find_all_children_parameters.append([_file, _network_os])
for _file in glob.glob(f"{MOCK_DIR}/find_children_w_parents/{_network_os}/*{TXT_FILE}"):
find_children_w_parents_parameters.append([_file, _network_os])
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is just changing network_os to _network_os as the loop variable so that we don't perpetuate copy/pasting the same pylint disable comment over and over...



@pytest.mark.parametrize("_file, network_os", base_parameters)
def test_parser(_file, network_os, get_text_data, get_python_data): # pylint: disable=redefined-outer-name
def test_parser(_file, network_os, get_text_data, get_python_data):
truncate_file = os.path.join(MOCK_DIR, "base", _file[: -len(TXT_FILE)])

device_cfg = get_text_data(os.path.join(MOCK_DIR, "base", _file))
Expand All @@ -33,7 +34,7 @@ def test_parser(_file, network_os, get_text_data, get_python_data): # pylint: d


@pytest.mark.parametrize("_file, network_os", find_all_children_parameters)
def test_find_all_children(_file, network_os, get_text_data, get_json_data): # pylint: disable=redefined-outer-name
def test_find_all_children(_file, network_os, get_text_data, get_json_data):
truncate_file = os.path.join(MOCK_DIR, "find_all_children", _file[: -len(TXT_FILE)])

device_cfg = get_text_data(os.path.join(MOCK_DIR, "find_all_children", _file))
Expand All @@ -44,7 +45,7 @@ def test_find_all_children(_file, network_os, get_text_data, get_json_data): #


@pytest.mark.parametrize("_file, network_os", find_children_w_parents_parameters)
def test_find_children_w_parents(_file, network_os, get_text_data, get_json_data): # pylint: disable=redefined-outer-name
def test_find_children_w_parents(_file, network_os, get_text_data, get_json_data):
truncate_file = os.path.join(MOCK_DIR, "find_children_w_parents", _file[: -len(TXT_FILE)])

device_cfg = get_text_data(os.path.join(MOCK_DIR, "find_children_w_parents", _file))
Expand Down Expand Up @@ -81,7 +82,7 @@ def test_duplicate_line():


@pytest.mark.parametrize("network_os", ["cisco_ios", "arista_eos", "cisco_iosxr"])
def test_leading_spaces_config_start(network_os): # pylint: disable=redefined-outer-name
def test_leading_spaces_config_start(network_os):
logging = (
"! Command: show running-config\n"
" 24.1.4\n"
Expand All @@ -95,3 +96,11 @@ def test_leading_spaces_config_start(network_os): # pylint: disable=redefined-o
)
with pytest.raises(IndexError, match=r".*Validate the first line does not begin with a space.*"):
compliance.parser_map[network_os](logging).config_lines # pylint: disable=expression-not-assigned


@pytest.mark.parametrize("network_os", all_network_os)
def test_empty_config(network_os):
"Test that an empty config returns an empty list and does not raise an error."
config = ""
os_parser = compliance.parser_map[network_os]
assert os_parser(config).config_lines == []