summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/container.xml.in15
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_ospf.py20
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py7
-rwxr-xr-xsrc/helpers/vyos_config_sync.py48
-rwxr-xr-xsrc/services/vyos-http-api-server2
5 files changed, 67 insertions, 25 deletions
diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in
index d0af0900a..7e1f4811a 100644
--- a/interface-definitions/container.xml.in
+++ b/interface-definitions/container.xml.in
@@ -128,7 +128,17 @@
</leafNode>
<leafNode name="image">
<properties>
- <help>Image name in the hub-registry</help>
+ <help>Container image to use</help>
+ <completionHelp>
+ <script>sudo podman image list --format "{{.Repository}}:{{.Tag}}"</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Image name in the hub-registry</description>
+ </valueHelp>
+ <constraint>
+ <regex>[[:ascii:]]{1,255}</regex>
+ </constraint>
</properties>
</leafNode>
<leafNode name="command">
@@ -165,6 +175,9 @@
<format>txt</format>
<description>Set label option value</description>
</valueHelp>
+ <constraint>
+ <regex>[[:ascii:]]{1,255}</regex>
+ </constraint>
</properties>
</leafNode>
</children>
diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py
index 82fb96754..1b9cc50fe 100755
--- a/smoketest/scripts/cli/test_protocols_ospf.py
+++ b/smoketest/scripts/cli/test_protocols_ospf.py
@@ -540,5 +540,25 @@ class TestProtocolsOSPF(VyOSUnitTestSHIM.TestCase):
for router_id in router_ids:
self.assertIn(f' graceful-restart helper enable {router_id}', frrconfig)
+ def test_ospf_17_duplicate_area_network(self):
+ area0 = '0'
+ area1 = '1'
+ network = '10.0.0.0/8'
+
+ self.cli_set(base_path + ['area', area0, 'network', network])
+
+ # we can not have the same network defined on two areas
+ self.cli_set(base_path + ['area', area1, 'network', network])
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+ self.cli_delete(base_path + ['area', area0])
+
+ self.cli_commit()
+
+ # Verify FRR ospfd configuration
+ frrconfig = self.getFRRconfig('router ospf', daemon=PROCESS_NAME)
+ self.assertIn(f'router ospf', frrconfig)
+ self.assertIn(f' network {network} area {area1}', frrconfig)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index 93fc4dba6..ee29f8198 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -129,6 +129,7 @@ def verify(ospf):
# Validate if configured Access-list exists
if 'area' in ospf:
+ networks = []
for area, area_config in ospf['area'].items():
if 'import_list' in area_config:
acl_import = area_config['import_list']
@@ -137,6 +138,12 @@ def verify(ospf):
acl_export = area_config['export_list']
if acl_export: verify_access_list(acl_export, ospf)
+ if 'network' in area_config:
+ for network in area_config['network']:
+ if network in networks:
+ raise ConfigError(f'Network "{network}" already defined in different area!')
+ networks.append(network)
+
if 'interface' in ospf:
for interface, interface_config in ospf['interface'].items():
verify_interface_exists(interface)
diff --git a/src/helpers/vyos_config_sync.py b/src/helpers/vyos_config_sync.py
index 572fea61f..77f7cd810 100755
--- a/src/helpers/vyos_config_sync.py
+++ b/src/helpers/vyos_config_sync.py
@@ -61,14 +61,16 @@ def post_request(url: str,
-def retrieve_config(section: str = None) -> Optional[Dict[str, Any]]:
+def retrieve_config(section: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
"""Retrieves the configuration from the local server.
Args:
- section: str: The section of the configuration to retrieve. Default is None.
+ section: List[str]: The section of the configuration to retrieve.
+ Default is None.
Returns:
- Optional[Dict[str, Any]]: The retrieved configuration as a dictionary, or None if an error occurred.
+ Optional[Dict[str, Any]]: The retrieved configuration as a
+ dictionary, or None if an error occurred.
"""
if section is None:
section = []
@@ -83,23 +85,21 @@ def retrieve_config(section: str = None) -> Optional[Dict[str, Any]]:
def set_remote_config(
address: str,
key: str,
- op: str,
- path: str = None,
- section: Optional[str] = None) -> Optional[Dict[str, Any]]:
+ commands: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
"""Loads the VyOS configuration in JSON format to a remote host.
Args:
address (str): The address of the remote host.
key (str): The key to use for loading the configuration.
- path (Optional[str]): The path of the configuration. Default is None.
- section (Optional[str]): The section of the configuration to load. Default is None.
+ commands (list): List of set/load commands for request, given as:
+ [{'op': str, 'path': list[str], 'section': dict},
+ ...]
Returns:
- Optional[Dict[str, Any]]: The response from the remote host as a dictionary, or None if an error occurred.
+ Optional[Dict[str, Any]]: The response from the remote host as a
+ dictionary, or None if a RequestException occurred.
"""
- if path is None:
- path = []
headers = {'Content-Type': 'application/json'}
# Disable the InsecureRequestWarning
@@ -107,9 +107,7 @@ def set_remote_config(
url = f'https://{address}/configure-section'
data = json.dumps({
- 'op': mode,
- 'path': path,
- 'section': section,
+ 'commands': commands,
'key': key
})
@@ -122,14 +120,14 @@ def set_remote_config(
return None
-def is_section_revised(section: str) -> bool:
+def is_section_revised(section: List[str]) -> bool:
from vyos.config_mgmt import is_node_revised
return is_node_revised(section)
def config_sync(secondary_address: str,
secondary_key: str,
- sections: List[list],
+ sections: List[list[str]],
mode: str):
"""Retrieve a config section from primary router in JSON format and send it to
secondary router
@@ -142,21 +140,25 @@ def config_sync(secondary_address: str,
)
# Sync sections ("nat", "firewall", etc)
+ commands = []
for section in sections:
config_json = retrieve_config(section=section)
# Check if config path deesn't exist, for example "set nat"
# we set empty value for config_json data
# As we cannot send to the remote host section "nat None" config
if not config_json:
- config_json = ""
+ config_json = {}
logger.debug(
f"Retrieved config for section '{section}': {config_json}")
- set_config = set_remote_config(address=secondary_address,
- key=secondary_key,
- op=mode,
- path=section,
- section=config_json)
- logger.debug(f"Set config for section '{section}': {set_config}")
+
+ d = {'op': mode, 'path': section, 'section': config_json}
+ commands.append(d)
+
+ set_config = set_remote_config(address=secondary_address,
+ key=secondary_key,
+ commands=commands)
+
+ logger.debug(f"Set config for sections '{sections}': {set_config}")
if __name__ == '__main__':
diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server
index a7b14a1a3..77870a84c 100755
--- a/src/services/vyos-http-api-server
+++ b/src/services/vyos-http-api-server
@@ -463,7 +463,7 @@ def _configure_op(data: Union[ConfigureModel, ConfigureListModel,
endpoint = request.url.path
# Allow users to pass just one command
- if not isinstance(data, ConfigureListModel):
+ if not isinstance(data, (ConfigureListModel, ConfigSectionListModel)):
data = [data]
else:
data = data.commands