Skip to content

Commit

Permalink
Support disable/enable syslog rate limit feature (sonic-net#3072)
Browse files Browse the repository at this point in the history
Depends on PR sonic-net/sonic-buildimage#17458

What I did
Add CLIs to enable/disable containercfgd to optimize warm/fast boot path

How I did it
Add CLIs to enable/disable containercfgd

How to verify it
unit test
manual test
  • Loading branch information
Junchao-Mellanox authored and mssonicbld committed Dec 25, 2023
1 parent b0908bd commit fc4b333
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 0 deletions.
83 changes: 83 additions & 0 deletions config/syslog.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,3 +471,86 @@ def rate_limit_container(db, service_name, interval, burst):
feature_data = db.cfgdb.get_table(syslog_common.FEATURE_TABLE)
syslog_common.service_validator(feature_data, service_name)
syslog_common.save_rate_limit_to_db(db, service_name, interval, burst, log)


@syslog.group(
name="rate-limit-feature",
cls=clicommon.AliasedGroup
)
def rate_limit_feature():
""" Configure syslog rate limit feature """
pass


@rate_limit_feature.command("enable")
@clicommon.pass_db
def enable_rate_limit_feature(db):
""" Enable syslog rate limit feature """
feature_data = db.cfgdb.get_table(syslog_common.FEATURE_TABLE)
for feature_name in feature_data.keys():
click.echo(f'Enabling syslog rate limit feature for {feature_name}')
output, _ = clicommon.run_command(['docker', 'ps', '-q', '-f', 'status=running', '-f', f'name={feature_name}'], return_cmd=True)
if not output:
click.echo(f'{feature_name} is not running, ignoring...')
continue

output, _ = clicommon.run_command(['docker', 'exec', '-i', feature_name, 'supervisorctl', 'status', 'containercfgd'],
ignore_error=True, return_cmd=True)
if 'no such process' not in output:
click.echo(f'Syslog rate limit feature is already enabled in {feature_name}, ignoring...')
continue

commands = [
['docker', 'cp', '/usr/share/sonic/templates/containercfgd.conf', f'{feature_name}:/etc/supervisor/conf.d/'],
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'reread'],
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'update'],
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'start', 'containercfgd']
]

failed = False
for command in commands:
output, ret = clicommon.run_command(command, return_cmd=True)
if ret != 0:
failed = True
click.echo(f'Enable syslog rate limit feature for {feature_name} failed - {output}')
break

if not failed:
click.echo(f'Enabled syslog rate limit feature for {feature_name}')


@rate_limit_feature.command("disable")
@clicommon.pass_db
def disable_rate_limit_feature(db):
""" Disable syslog rate limit feature """
feature_data = db.cfgdb.get_table(syslog_common.FEATURE_TABLE)
for feature_name in feature_data.keys():
click.echo(f'Disabling syslog rate limit feature for {feature_name}')
output, _ = clicommon.run_command(['docker', 'ps', '-q', '-f', 'status=running', '-f', f'name={feature_name}'], return_cmd=True)
if not output:
click.echo(f'{feature_name} is not running, ignoring...')
continue

output, _ = clicommon.run_command(['docker', 'exec', '-i', feature_name, 'supervisorctl', 'status', 'containercfgd'],
ignore_error=True, return_cmd=True)
if 'no such process' in output:
click.echo(f'Syslog rate limit feature is already disabled in {feature_name}, ignoring...')
continue

commands = [
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'stop', 'containercfgd'],
['docker', 'exec', '-i', feature_name, 'rm', '-f', '/etc/supervisor/conf.d/containercfgd.conf'],
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'reread'],
['docker', 'exec', '-i', feature_name, 'supervisorctl', 'update']
]
failed = False
for command in commands:
output, ret = clicommon.run_command(command, return_cmd=True)
if ret != 0:
failed = True
click.echo(f'Disable syslog rate limit feature for {feature_name} failed - {output}')
break

if not failed:
click.echo(f'Disabled syslog rate limit feature for {feature_name}')

27 changes: 27 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -9893,6 +9893,33 @@ This command is used to configure syslog rate limit for containers.
admin@sonic:~$ sudo config syslog rate-limit-container bgp --interval 300 --burst 20000
```
**config syslog rate-limit-feature enable**
This command is used to enable syslog rate limit feature.
- Usage:
```
config syslog rate-limit-feature enable
```
- Example:
```
admin@sonic:~$ sudo config syslog rate-limit-feature enable
```
**config syslog rate-limit-feature disable**
This command is used to disable syslog rate limit feature.
- Usage:
```
config syslog rate-limit-feature disable
```
- Example:
```
admin@sonic:~$ sudo config syslog rate-limit-feature disable
```
Go Back To [Beginning of the document](#) or [Beginning of this section](#syslog)
Expand Down
86 changes: 86 additions & 0 deletions tests/syslog_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,89 @@ def test_show_syslog_rate_limit_container_negative(self, subcommand):
logger.debug("\n" + result.output)
logger.debug(result.exit_code)
assert result.exit_code != SUCCESS

@mock.patch('config.syslog.clicommon.run_command')
def test_enable_syslog_rate_limit_feature(self, mock_run):
db = Db()
db.cfgdb.set_entry(FEATURE_TABLE, 'bgp', {SUPPORT_RATE_LIMIT: 'true',
'state': 'enabled'})

runner = CliRunner()

mock_run.return_value = ('no such process', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["enable"], obj=db
)
assert result.exit_code == SUCCESS

# container not run
mock_run.return_value = ('', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["enable"], obj=db
)
assert result.exit_code == SUCCESS

# process already running
mock_run.return_value = ('something', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["enable"], obj=db
)
assert result.exit_code == SUCCESS

# one command fail
def side_effect(*args, **kwargs):
side_effect.call_count += 1
if side_effect.call_count <= 2:
return 'no such process', 0
else:
return '', -1
side_effect.call_count = 0
mock_run.side_effect = side_effect
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["enable"], obj=db
)
assert result.exit_code == SUCCESS


@mock.patch('config.syslog.clicommon.run_command')
def test_disable_syslog_rate_limit_feature(self, mock_run):
db = Db()
db.cfgdb.set_entry(FEATURE_TABLE, 'bgp', {SUPPORT_RATE_LIMIT: 'true',
'state': 'enabled'})

runner = CliRunner()

mock_run.return_value = ('something', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["disable"], obj=db
)
assert result.exit_code == SUCCESS

# container not run
mock_run.return_value = ('', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["disable"], obj=db
)
assert result.exit_code == SUCCESS

# process already stopped
mock_run.return_value = ('no such process', 0)
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["disable"], obj=db
)
assert result.exit_code == SUCCESS

# one command fail
def side_effect(*args, **kwargs):
side_effect.call_count += 1
if side_effect.call_count <= 2:
return 'something', 0
else:
return '', -1
side_effect.call_count = 0
mock_run.side_effect = side_effect
result = runner.invoke(
config.config.commands["syslog"].commands["rate-limit-feature"].commands["disable"], obj=db
)
assert result.exit_code == SUCCESS

0 comments on commit fc4b333

Please sign in to comment.