Skip to content

Commit

Permalink
[config] Generate sysinfo as needed when override config (#2836)
Browse files Browse the repository at this point in the history
ADO: 17921518

What I did
The generated Golden Config will not have knowledge of configs that are produced in run time, such as mac and platform.
Generate that info in Override Config if missing.

How I did it
Reuse the mac and platform in existing device runnning config and generate that if missing.

How to verify it
Unit test
  • Loading branch information
wen587 committed May 25, 2023
1 parent f258e2a commit d5544b4
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 0 deletions.
43 changes: 43 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,47 @@ def override_config_by(golden_config_path):
return


# This funtion is to generate sysinfo if that is missing in config_input.
# It will keep the same with sysinfo in cur_config if sysinfo exists.
# Otherwise it will modify config_input with generated sysinfo.
def generate_sysinfo(cur_config, config_input, ns=None):
# Generate required sysinfo for Golden Config.
device_metadata = config_input.get('DEVICE_METADATA')

if not device_metadata or 'localhost' not in device_metadata:
return

mac = None
platform = None
cur_device_metadata = cur_config.get('DEVICE_METADATA')

# Reuse current config's mac and platform. Generate if absent
if cur_device_metadata is not None:
mac = cur_device_metadata.get('localhost', {}).get('mac')
platform = cur_device_metadata.get('localhost', {}).get('platform')

if not mac:
if ns:
asic_role = device_metadata.get('localhost', {}).get('sub_role')
switch_type = device_metadata.get('localhost', {}).get('switch_type')

if ((switch_type is not None and switch_type.lower() == "chassis-packet") or
(asic_role is not None and asic_role.lower() == "backend")):
mac = device_info.get_system_mac(namespace=ns)
else:
mac = device_info.get_system_mac()
else:
mac = device_info.get_system_mac()

if not platform:
platform = device_info.get_platform()

device_metadata['localhost']['mac'] = mac
device_metadata['localhost']['platform'] = platform

return


#
# 'override-config-table' command ('config override-config-table ...')
#
Expand Down Expand Up @@ -1865,6 +1906,8 @@ def override_config_table(db, input_config_db, dry_run):
ns_config_input = config_input["localhost"]
else:
ns_config_input = config_input[ns]
# Generate sysinfo if missing in ns_config_input
generate_sysinfo(current_config, ns_config_input, ns)
else:
ns_config_input = config_input
updated_config = update_config(current_config, ns_config_input)
Expand Down
55 changes: 55 additions & 0 deletions tests/config_override_input/multi_asic_dm_gen_sysinfo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"localhost": {
"DEVICE_METADATA": {
"localhost": {
"default_bgp_status": "down",
"default_pfcwd_status": "enable",
"deployment_id": "1",
"docker_routing_config_mode": "separated",
"hostname": "sonic-switch",
"hwsku": "Mellanox-SN3800-D112C8",
"peer_switch": "sonic-switch",
"type": "ToRRouter",
"suppress-fib-pending": "enabled"
}
}
},
"asic0": {
"DEVICE_METADATA": {
"localhost": {
"asic_id": "01.00.0",
"asic_name": "asic0",
"bgp_asn": "65100",
"cloudtype": "None",
"default_bgp_status": "down",
"default_pfcwd_status": "enable",
"deployment_id": "None",
"docker_routing_config_mode": "separated",
"hostname": "sonic",
"hwsku": "multi_asic",
"region": "None",
"sub_role": "FrontEnd",
"type": "LeafRouter"
}
}
},
"asic1": {
"DEVICE_METADATA": {
"localhost": {
"asic_id": "08:00.0",
"asic_name": "asic1",
"bgp_asn": "65100",
"cloudtype": "None",
"default_bgp_status": "down",
"default_pfcwd_status": "enable",
"deployment_id": "None",
"docker_routing_config_mode": "separated",
"hostname": "sonic",
"hwsku": "multi_asic",
"region": "None",
"sub_role": "BackEnd",
"type": "LeafRouter"
}
}
}
}
63 changes: 63 additions & 0 deletions tests/config_override_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
FINAL_CONFIG_YANG_FAILURE = os.path.join(DATA_DIR, "final_config_yang_failure.json")
MULTI_ASIC_MACSEC_OV = os.path.join(DATA_DIR, "multi_asic_macsec_ov.json")
MULTI_ASIC_DEVICE_METADATA_RM = os.path.join(DATA_DIR, "multi_asic_dm_rm.json")
MULTI_ASIC_DEVICE_METADATA_GEN_SYSINFO = os.path.join(DATA_DIR, "multi_asic_dm_gen_sysinfo.json")

# Load sonic-cfggen from source since /usr/local/bin/sonic-cfggen does not have .py extension.
sonic_cfggen = load_module_from_source('sonic_cfggen', '/usr/local/bin/sonic-cfggen')
Expand Down Expand Up @@ -318,6 +319,68 @@ def read_json_file_side_effect(filename):
for ns, config_db in cfgdb_clients.items():
assert 'DEVICE_METADATA' not in config_db.get_config()

def test_device_metadata_keep_sysinfo(self):
def read_json_file_side_effect(filename):
with open(MULTI_ASIC_DEVICE_METADATA_GEN_SYSINFO, "r") as f:
device_metadata = json.load(f)
return device_metadata
db = Db()
cfgdb_clients = db.cfgdb_clients

# Save original sysinfo in dict, compare later to see if it is override
orig_sysinfo = {}
for ns, config_db in cfgdb_clients.items():
platform = config_db.get_config()['DEVICE_METADATA']['localhost'].get('platform')
mac = config_db.get_config()['DEVICE_METADATA']['localhost'].get('mac')
orig_sysinfo[ns] = {}
orig_sysinfo[ns]['platform'] = platform
orig_sysinfo[ns]['mac'] = mac

with mock.patch('config.main.read_json_file',
mock.MagicMock(side_effect=read_json_file_side_effect)):
runner = CliRunner()
result = runner.invoke(config.config.commands["override-config-table"],
['golden_config_db.json'], obj=db)
assert result.exit_code == 0

for ns, config_db in cfgdb_clients.items():
platform = config_db.get_config()['DEVICE_METADATA']['localhost'].get('platform')
mac = config_db.get_config()['DEVICE_METADATA']['localhost'].get('mac')
assert platform == orig_sysinfo[ns]['platform']
assert mac == orig_sysinfo[ns]['mac']

def test_device_metadata_gen_sysinfo(self):
def read_json_file_side_effect(filename):
with open(MULTI_ASIC_DEVICE_METADATA_GEN_SYSINFO, "r") as f:
device_metadata = json.load(f)
return device_metadata
db = Db()
cfgdb_clients = db.cfgdb_clients

# Remove original sysinfo and check if use generated ones
for ns, config_db in cfgdb_clients.items():
metadata = config_db.get_config()['DEVICE_METADATA']['localhost']
metadata.pop('platform', None)
metadata.pop('mac', None)
config_db.set_entry('DEVICE_METADATA', 'localhost', metadata)

with mock.patch('config.main.read_json_file',
mock.MagicMock(side_effect=read_json_file_side_effect)),\
mock.patch('sonic_py_common.device_info.get_platform',
return_value="multi_asic"),\
mock.patch('sonic_py_common.device_info.get_system_mac',
return_value="11:22:33:44:55:66"):
runner = CliRunner()
result = runner.invoke(config.config.commands["override-config-table"],
['golden_config_db.json'], obj=db)
assert result.exit_code == 0

for ns, config_db in cfgdb_clients.items():
platform = config_db.get_config()['DEVICE_METADATA']['localhost'].get('platform')
mac = config_db.get_config()['DEVICE_METADATA']['localhost'].get('mac')
assert platform == "multi_asic"
assert mac == "11:22:33:44:55:66"


@classmethod
def teardown_class(cls):
Expand Down

0 comments on commit d5544b4

Please sign in to comment.