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

[GCU] Supporting Groupings during path-xpath translation #2044

Merged
merged 3 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
58 changes: 57 additions & 1 deletion generic_config_updater/gu_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ def create_xpath(self, tokens):

return f"{PathAddressing.XPATH_SEPARATOR}{PathAddressing.XPATH_SEPARATOR.join(str(t) for t in tokens)}"

def _create_sonic_yang_with_loaded_models(self):
return self.config_wrapper.create_sonic_yang_with_loaded_models()

def find_ref_paths(self, path, config):
"""
Finds the paths referencing any line under the given 'path' within the given 'config'.
Expand Down Expand Up @@ -401,7 +404,7 @@ def find_ref_paths(self, path, config):
return self._find_leafref_paths(path, config)

def _find_leafref_paths(self, path, config):
sy = self.config_wrapper.create_sonic_yang_with_loaded_models()
sy = self._create_sonic_yang_with_loaded_models()

tmp_config = copy.deepcopy(config)

Expand Down Expand Up @@ -547,6 +550,13 @@ def _get_xpath_tokens_from_leaf(self, model, token_index, path_tokens, config):
# /module-name:container/leaf-list[.='val']
# Source: Check examples in https://netopeer.liberouter.org/doc/libyang/master/html/howto_x_path.html
return [f"{token}[.='{value}']"]

# checking 'uses' statement
if not isinstance(config[token], list): # leaf-list under uses is not supported yet in sonic_yang
table = path_tokens[0]
uses_leaf_model = self._get_uses_leaf_model(model, table, token)
if uses_leaf_model:
return [token]

raise ValueError("Token not found")

Expand Down Expand Up @@ -712,6 +722,13 @@ def _get_path_tokens_from_leaf(self, model, token_index, xpath_tokens, config):
list_idx = list_config.index(leaf_list_value)
return [leaf_list_name, list_idx]

# checking 'uses' statement
if not isinstance(config[leaf_list_name], list): # leaf-list under uses is not supported yet in sonic_yang
table = xpath_tokens[1]
uses_leaf_model = self._get_uses_leaf_model(model, table, token)
if uses_leaf_model:
return [token]

raise Exception("no leaf")

def _extract_key_dict(self, list_token):
Expand Down Expand Up @@ -746,6 +763,45 @@ def _get_model(self, model, name):

return None

def _get_uses_leaf_model(self, model, table, token):
"""
Getting leaf model in uses model matching the given token.
"""
uses_s = model.get('uses')
if not uses_s:
return None

# a model can be a single dict or a list of dictionaries, unify to a list of dictionaries
if not isinstance(uses_s, list):
uses_s = [uses_s]

sy = self._create_sonic_yang_with_loaded_models()
# find yang module for current table
table_module = sy.confDbYangMap[table]['yangModule']
# uses Example: "@name": "bgpcmn:sonic-bgp-cmn"
for uses in uses_s:
ghooo marked this conversation as resolved.
Show resolved Hide resolved
if not isinstance(uses, dict):
raise GenericConfigUpdaterError(f"'uses' is expected to be a dictionary found '{type(uses)}'.\n" \
f" uses: {uses}\n model: {model}\n table: {table}\n token: {token}")

# Assume ':' means reference to another module
if ':' in uses['@name']:
name_parts = uses['@name'].split(':')
prefix = name_parts[0].strip()
uses_module_name = sy._findYangModuleFromPrefix(prefix, table_module)
grouping = name_parts[-1].strip()
else:
uses_module_name = table_module['@name']
grouping = uses['@name']

leafs = sy.preProcessedYang['grouping'][uses_module_name][grouping]

leaf_model = self._get_model(leafs, token)
if leaf_model:
return leaf_model

return None

class TitledLogger(logger.Logger):
def __init__(self, syslog_identifier, title, verbose, print_all_to_console):
super().__init__(syslog_identifier)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"BGP_NEIGHBOR": {
ghooo marked this conversation as resolved.
Show resolved Hide resolved
"1.2.3.4": {
"admin_status": "up",
"asn": "65000",
"holdtime": "10",
"keepalive": "3",
"local_addr": "10.0.0.10",
"name": "ARISTA03T1",
"nhopself": "0",
"rrclient": "0"
},
"default|1.2.3.4": {
"local_asn": "65200",
"asn": "65100",
"name": "bgp peer 65100",
"ebgp_multihop_ttl": "3"
}
},
"BGP_MONITORS": {
"5.6.7.8": {
"admin_status": "up",
"asn": "65000",
"holdtime": "180",
"keepalive": "60",
"local_addr": "10.0.0.11",
"name": "BGPMonitor",
"nhopself": "0",
"rrclient": "0"
}
}
}
14 changes: 14 additions & 0 deletions tests/generic_config_updater/files/config_db_with_lldp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"LLDP": {
"GLOBAL": {
"mode": "TRANSMIT",
"enabled": "true",
"hello_time": "12",
"multiplier": "5",
"supp_mgmt_address_tlv": "true",
"supp_system_capabilities_tlv": "false",
"system_name": "sonic",
"system_description": "sonic-system"
}
}
}
24 changes: 24 additions & 0 deletions tests/generic_config_updater/gu_common_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,18 @@ def check(path, xpath, config=None):
check(path="/PORTCHANNEL_INTERFACE/PortChannel0001|1.1.1.1~124",
xpath="/sonic-portchannel:sonic-portchannel/PORTCHANNEL_INTERFACE/PORTCHANNEL_INTERFACE_IPPREFIX_LIST[name='PortChannel0001'][ip_prefix='1.1.1.1/24']",
config=Files.CONFIG_DB_WITH_PORTCHANNEL_INTERFACE)
check(path="/BGP_NEIGHBOR/1.2.3.4/holdtime",
xpath="/sonic-bgp-neighbor:sonic-bgp-neighbor/BGP_NEIGHBOR/BGP_NEIGHBOR_TEMPLATE_LIST[neighbor='1.2.3.4']/holdtime",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(path="/BGP_NEIGHBOR/default|1.2.3.4/asn",
xpath="/sonic-bgp-neighbor:sonic-bgp-neighbor/BGP_NEIGHBOR/BGP_NEIGHBOR_LIST[vrf_name='default'][neighbor='1.2.3.4']/asn",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(path="/BGP_MONITORS/5.6.7.8/name",
xpath="/sonic-bgp-monitor:sonic-bgp-monitor/BGP_MONITORS/BGP_MONITORS_LIST[addr='5.6.7.8']/name",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(path="/LLDP/GLOBAL/mode",
ghooo marked this conversation as resolved.
Show resolved Hide resolved
xpath="/sonic-lldp:sonic-lldp/LLDP/GLOBAL/mode",
config=Files.CONFIG_DB_WITH_LLDP)

def test_convert_xpath_to_path(self):
def check(xpath, path, config=None):
Expand Down Expand Up @@ -798,6 +810,18 @@ def check(xpath, path, config=None):
check(xpath="/sonic-portchannel:sonic-portchannel/PORTCHANNEL_INTERFACE/PORTCHANNEL_INTERFACE_IPPREFIX_LIST[name='PortChannel0001'][ip_prefix='1.1.1.1/24']",
path="/PORTCHANNEL_INTERFACE/PortChannel0001|1.1.1.1~124",
config=Files.CONFIG_DB_WITH_PORTCHANNEL_INTERFACE)
check(xpath="/sonic-bgp-neighbor:sonic-bgp-neighbor/BGP_NEIGHBOR/BGP_NEIGHBOR_TEMPLATE_LIST[neighbor='1.2.3.4']/holdtime",
path="/BGP_NEIGHBOR/1.2.3.4/holdtime",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(xpath="/sonic-bgp-neighbor:sonic-bgp-neighbor/BGP_NEIGHBOR/BGP_NEIGHBOR_LIST[vrf_name='default'][neighbor='1.2.3.4']/asn",
path="/BGP_NEIGHBOR/default|1.2.3.4/asn",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(xpath="/sonic-bgp-monitor:sonic-bgp-monitor/BGP_MONITORS/BGP_MONITORS_LIST[addr='5.6.7.8']/name",
path="/BGP_MONITORS/5.6.7.8/name",
config=Files.CONFIG_DB_WITH_BGP_NEIGHBOR)
check(xpath="/sonic-lldp:sonic-lldp/LLDP/GLOBAL/mode",
path="/LLDP/GLOBAL/mode",
config=Files.CONFIG_DB_WITH_LLDP)

def test_has_path(self):
def check(config, path, expected):
Expand Down