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

[Banner] Added CLI commands to configure Banner and display current configuration #3021

Merged
merged 5 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8053,5 +8053,58 @@ def max_sessions(max_sessions):
{'max_sessions': max_sessions})


#
# 'banner' group ('config banner ...')
#
@config.group()
def banner():
"""Configuring system banner messages"""
pass


@banner.command()
@click.argument('state', metavar='<enabled|disabled>', required=True, type=click.Choice(['enabled', 'disabled']))
def state(state):
"""Set banner feature state"""

config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry(swsscommon.CFG_BANNER_MESSAGE_TABLE_NAME, 'global',
Copy link
Contributor

@qiluo-msft qiluo-msft Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CFG_BANNER_MESSAGE_TABLE_NAME

Why not use FEATURE table? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FEATURE table was designed for SONiC App extensions features. The Banner feature is not the case...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see many features are not SONiC App extensions feature there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see many features are not SONiC App extensions feature there.

Sure. But we need to keep separate. In that case, it is much easier to handle. In hostcfgd we have a logic to handle FEATURE table changes. It would be overload to add additional logic to handle the banner there.
So for that, we added a new table and new subscriber in hostcfgd to handle it separately. The code looks much clearer and it is consistent over other features: NTP, RSYSLOG, SSH, etc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qiluo-msft FEATURE table in general is associated with an application with a docker today. We have a dedicated application featured which listens to feature table and enables system services. We also have coppmgr using this logic to enable traps. Adding entry to feature table when there is no associated docker will lead to errors in some flows and currently it is not supported. Hence in this scenario it is advisable to use a separate table.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qiluo-msft please see @dgsudharsan answer. I agree with him

{'state': state})


@banner.command()
@click.argument('message', metavar='<message>', required=True)
def login(message):
"""Set login message"""

config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry(swsscommon.CFG_BANNER_MESSAGE_TABLE_NAME, 'global',
{'login': message})


@banner.command()
@click.argument('message', metavar='<message>', required=True)
def logout(message):
"""Set logout message"""

config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry(swsscommon.CFG_BANNER_MESSAGE_TABLE_NAME, 'global',
{'logout': message})


@banner.command()
@click.argument('message', metavar='<message>', required=True)
def motd(message):
"""Set message of the day"""

config_db = ConfigDBConnector()
config_db.connect()
config_db.mod_entry(swsscommon.CFG_BANNER_MESSAGE_TABLE_NAME, 'global',
{'motd': message})


if __name__ == '__main__':
config()
89 changes: 89 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@
* [Static DNS show command](#static-dns-show-command)
* [Wake-on-LAN Commands](#wake-on-lan-commands)
* [Send Wake-on-LAN Magic Packet command](#send-wake-on-lan-magic-packet-command)
* [Banner Commands](#banner-commands)
* [Banner config commands](#banner-config-commands)
* [Banner show command](#banner-show-command)

## Document History

Expand Down Expand Up @@ -13857,3 +13860,89 @@ Sending 3 magic packet to 11:33:55:77:99:bb via interface Vlan1000
```

For the 4th example, it specifise 2 target MAC addresses and `count` is 3. So it'll send 6 magic packets in total.

# Banner Commands

This sub-section explains the list of the configuration options available for Banner feature.

## Banner config commands

- Set banner feature state

```
admin@sonic:~$ config banner state <enabled|disabled>
Usage: config config banner state <enabled|disabled>

Set banner feature state

Options:
-?, -h, --help Show this message and exit.
```

- Set login message

```
admin@sonic:~$ config banner login <message>
Usage: config banner login <message>

Set login message

Options:
-?, -h, --help Show this message and exit.
```

- Set logout message

```
admin@sonic:~$ config banner logout <message>
Usage: config banner logout <message>

Set logout message

Options:
-?, -h, --help Show this message and exit.
```

- Set message of the day

```
admin@sonic:~$ config banner motd <message>
Usage: config banner motd <message>

Set message of the day

Options:
-?, -h, --help Show this message and exit.
```

## Banner show command

- how banner messages

```
admin@sonic:~$ show banner
Usage: show banner

Show banner messages

Options:
-h, -?, --help Show this message and exit.
```
```
admin@sonic:~$ show banner
state login motd logout
------- ------- ------------------------------------------------ --------
enabled Login You are on
Message ____ ___ _ _ _ ____
/ ___| / _ \| \ | (_)/ ___|
\___ \| | | | \| | | |
___) | |_| | |\ | | |___
|____/ \___/|_| \_|_|\____|

-- Software for Open Networking in the Cloud --

Unauthorized access and/or use are prohibited.
All access and/or use are subject to monitoring.

Help: https://sonic-net.github.io/SONiC/
```
20 changes: 20 additions & 0 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2616,6 +2616,26 @@ def ssh(db):
click.echo(tabulate(configuration, headers=hdrs, tablefmt='simple', missingval=''))


#
# 'banner' command group ("show banner ...")
#
@cli.group('banner', invoke_without_command=True)
@clicommon.pass_db
def banner(db):
"""Show banner messages"""

banner_table = db.cfgdb.get_entry('BANNER_MESSAGE', 'global')

hdrs = ['state', 'login', 'motd', 'logout']
data = []

for key in hdrs:
data.append(banner_table.get(key, '').replace('\\n', '\n'))

messages = [data]
click.echo(tabulate(messages, headers=hdrs, tablefmt='simple', missingval=''))


# Load plugins and register them
helper = util_base.UtilHelper()
helper.load_and_register_plugins(plugins, cli)
Expand Down
60 changes: 60 additions & 0 deletions tests/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3877,3 +3877,63 @@ def teardown_class(cls):
from .mock_tables import mock_single_asic
importlib.reload(mock_single_asic)
dbconnector.load_database_config()


class TestConfigBanner(object):
@classmethod
def setup_class(cls):
print('SETUP')
import config.main
importlib.reload(config.main)

@patch('utilities_common.cli.run_command',
mock.MagicMock(side_effect=mock_run_command_side_effect))
def test_banner_state(self):
runner = CliRunner()
obj = {'db': Db().cfgdb}

result = runner.invoke(
config.config.commands['banner'].commands['state'],
['enabled'], obj=obj)

assert result.exit_code == 0

@patch('utilities_common.cli.run_command',
mock.MagicMock(side_effect=mock_run_command_side_effect))
def test_banner_login(self):
runner = CliRunner()
obj = {'db': Db().cfgdb}

result = runner.invoke(
config.config.commands['banner'].commands['login'],
['Login message'], obj=obj)

assert result.exit_code == 0

@patch('utilities_common.cli.run_command',
mock.MagicMock(side_effect=mock_run_command_side_effect))
def test_banner_logout(self):
runner = CliRunner()
obj = {'db': Db().cfgdb}

result = runner.invoke(
config.config.commands['banner'].commands['logout'],
['Logout message'], obj=obj)

assert result.exit_code == 0

@patch('utilities_common.cli.run_command',
mock.MagicMock(side_effect=mock_run_command_side_effect))
def test_banner_motd(self):
runner = CliRunner()
obj = {'db': Db().cfgdb}

result = runner.invoke(
config.config.commands['banner'].commands['motd'],
['Motd message'], obj=obj)

assert result.exit_code == 0

@classmethod
def teardown_class(cls):
print('TEARDOWN')
6 changes: 6 additions & 0 deletions tests/show_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,12 @@ def test_show_ztp(self, mock_run_command):
assert result.exit_code == 0
mock_run_command.assert_called_with(['ztp', 'status', '--verbose'], display_cmd=True)

@patch('show.main.run_command')
def test_show_banner(self, mock_run_command):
runner = CliRunner()
result = runner.invoke(show.cli.commands['banner'])
assert result.exit_code == 0

def teardown(self):
print('TEAR DOWN')

Expand Down
Loading