Skip to content

Commit

Permalink
Add YANG validation for config reload if file is given (sonic-net#3576)
Browse files Browse the repository at this point in the history
What I did
Add constraint for YANG when config reload, which is already enabled in load_minigraph

How I did it
Check YANG vaidation for the config

How to verify it
Unit test
  • Loading branch information
wen587 authored Oct 21, 2024
1 parent 4a6d121 commit 89bb87a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 9 deletions.
30 changes: 21 additions & 9 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,19 @@ def multiasic_write_to_db(filename, load_sysinfo):
migrate_db_to_lastest(ns)


def config_file_yang_validation(filename):
config_to_check = read_json_file(filename)
sy = sonic_yang.SonicYang(YANG_DIR)
sy.loadYangModel()
try:
sy.loadData(configdbJson=config_to_check)
sy.validate_data_tree()
except sonic_yang.SonicYangException as e:
click.secho("{} fails YANG validation! Error: {}".format(filename, str(e)),
fg='magenta')
raise click.Abort()


# This is our main entrypoint - the main 'config' command
@click.group(cls=clicommon.AbbreviationGroup, context_settings=CONTEXT_SETTINGS)
@click.pass_context
Expand Down Expand Up @@ -1810,6 +1823,13 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, force, file_form
click.echo("Input {} config file(s) separated by comma for multiple files ".format(num_cfg_file))
return

if filename is not None:
if multi_asic.is_multi_asic():
# Multiasic has not 100% fully validated. Thus pass here.
pass
else:
config_file_yang_validation(filename)

#Stop services before config push
if not no_service_restart:
log.log_notice("'reload' stopping services...")
Expand Down Expand Up @@ -2000,15 +2020,7 @@ def load_minigraph(db, no_service_restart, traffic_shift_away, override_config,
# Multiasic has not 100% fully validated. Thus pass here.
pass
else:
sy = sonic_yang.SonicYang(YANG_DIR)
sy.loadYangModel()
try:
sy.loadData(configdbJson=config_to_check)
sy.validate_data_tree()
except sonic_yang.SonicYangException as e:
click.secho("{} fails YANG validation! Error: {}".format(golden_config_path, str(e)),
fg='magenta')
raise click.Abort()
config_file_yang_validation(golden_config_path)

# Dependency check golden config json
if multi_asic.is_multi_asic():
Expand Down
28 changes: 28 additions & 0 deletions tests/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1384,6 +1384,34 @@ def test_reload_yang_config(self, get_cmd_module,
assert "\n".join([l.rstrip() for l in result.output.split('\n')]) \
== RELOAD_YANG_CFG_OUTPUT.format(config.SYSTEM_RELOAD_LOCK)

def test_reload_config_fails_yang_validation(self, get_cmd_module, setup_single_broadcom_asic):
with open(self.dummy_cfg_file, 'w') as f:
device_metadata = {
"DEVICE_METADATA": {
"localhost": {
"invalid_hwsku": "some_hwsku"
}
}
}
f.write(json.dumps(device_metadata))

with mock.patch(
"utilities_common.cli.run_command",
mock.MagicMock(side_effect=mock_run_command_side_effect)
):
(config, _) = get_cmd_module
runner = CliRunner()

result = runner.invoke(
config.config.commands["reload"],
[self.dummy_cfg_file, '-y', '-f'])

print(result.exit_code)
print(result.output)
traceback.print_tb(result.exc_info[2])
assert result.exit_code != 0
assert "fails YANG validation! Error" in result.output

@classmethod
def teardown_class(cls):
os.environ['UTILITIES_UNIT_TESTING'] = "0"
Expand Down

0 comments on commit 89bb87a

Please sign in to comment.