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

[cli/feature]: split feature into a separate file #1034

Merged
merged 3 commits into from
Aug 8, 2020
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
48 changes: 48 additions & 0 deletions config/feature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import click

from utilities_common.cli import AbbreviationGroup, pass_db

#
# 'feature' group ('config feature ...')
#
@click.group(cls=AbbreviationGroup, name='feature', invoke_without_command=False)
def feature():
"""Configure features"""
pass

#
# 'state' command ('config feature state ...')
#
@feature.command('state', short_help="Enable/disable a feature")
@click.argument('name', metavar='<feature-name>', required=True)
@click.argument('state', metavar='<state>', required=True, type=click.Choice(["enabled", "disabled"]))
@pass_db
def feature_state(db, name, state):
"""Enable/disable a feature"""
state_data = db.cfgdb.get_entry('FEATURE', name)

if not state_data:
click.echo("Feature '{}' doesn't exist".format(name))
sys.exit(1)

db.cfgdb.mod_entry('FEATURE', name, {'state': state})

#
# 'autorestart' command ('config feature autorestart ...')
#
@feature.command(name='autorestart', short_help="Enable/disable autosrestart of a feature")
@click.argument('name', metavar='<feature-name>', required=True)
@click.argument('autorestart', metavar='<autorestart>', required=True, type=click.Choice(["enabled", "disabled"]))
@pass_db
def feature_autorestart(db, name, autorestart):
"""Enable/disable autorestart of a feature"""
feature_table = db.cfgdb.get_table('FEATURE')
if not feature_table:
click.echo("Unable to retrieve feature table from Config DB.")
sys.exit(1)

if not feature_table.has_key(name):
click.echo("Unable to retrieve feature '{}'".format(name))
sys.exit(1)

db.cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart})
90 changes: 3 additions & 87 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
from swsssdk import ConfigDBConnector, SonicV2Connector, SonicDBConfig
from utilities_common.db import Db
from utilities_common.intf_filter import parse_interface_in_filter
from utilities_common.cli import AbbreviationGroup, pass_db

import aaa
import mlnx
import nat
import feature
from config_mgmt import ConfigMgmtDPB

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?'])
Expand Down Expand Up @@ -54,46 +56,6 @@

asic_type = None


class AbbreviationGroup(click.Group):
"""This subclass of click.Group supports abbreviated subgroup/subcommand names
"""

def get_command(self, ctx, cmd_name):
# Try to get builtin commands as normal
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv

# Allow automatic abbreviation of the command. "status" for
# instance will match "st". We only allow that however if
# there is only one command.
# If there are multiple matches and the shortest one is the common prefix of all the matches, return
# the shortest one
matches = []
shortest = None
for x in self.list_commands(ctx):
if x.lower().startswith(cmd_name.lower()):
matches.append(x)
if not shortest:
shortest = x
elif len(shortest) > len(x):
shortest = x

if not matches:
return None
elif len(matches) == 1:
return click.Group.get_command(self, ctx, matches[0])
else:
for x in matches:
if not x.startswith(shortest):
break
else:
return click.Group.get_command(self, ctx, shortest)

ctx.fail('Too many matches: %s' % ', '.join(sorted(matches)))


#
# Load breakout config file for Dynamic Port Breakout
#
Expand Down Expand Up @@ -922,10 +884,9 @@ def config(ctx):

ctx.obj = Db()

pass_db = click.make_pass_decorator(Db, ensure=True)

config.add_command(aaa.aaa)
config.add_command(aaa.tacacs)
config.add_command(feature.feature)
# === Add NAT Configuration ==========
config.add_command(nat.nat)

Expand Down Expand Up @@ -3838,50 +3799,5 @@ def delete(ctx):
sflow_tbl['global'].pop('agent_id')
config_db.set_entry('SFLOW', 'global', sflow_tbl['global'])

#
# 'feature' group ('config feature ...')
#
@config.group(cls=AbbreviationGroup, name='feature', invoke_without_command=False)
def feature():
"""Modify configuration of features"""
pass

#
# 'state' command ('config feature state ...')
#
@feature.command('state', short_help="Enable/disable a feature")
@click.argument('name', metavar='<feature-name>', required=True)
@click.argument('state', metavar='<state>', required=True, type=click.Choice(["enabled", "disabled"]))
@pass_db
def feature_state(db, name, state):
"""Enable/disable a feature"""
state_data = db.cfgdb.get_entry('FEATURE', name)

if not state_data:
click.echo("Feature '{}' doesn't exist".format(name))
sys.exit(1)

db.cfgdb.mod_entry('FEATURE', name, {'state': state})

#
# 'autorestart' command ('config feature autorestart ...')
#
@feature.command(name='autorestart', short_help="Enable/disable autosrestart of a feature")
@click.argument('name', metavar='<feature-name>', required=True)
@click.argument('autorestart', metavar='<autorestart>', required=True, type=click.Choice(["enabled", "disabled"]))
@pass_db
def feature_autorestart(db, name, autorestart):
"""Enable/disable autorestart of a feature"""
feature_table = db.cfgdb.get_table('FEATURE')
if not feature_table:
click.echo("Unable to retrieve feature table from Config DB.")
sys.exit(1)

if not feature_table.has_key(name):
click.echo("Unable to retrieve feature '{}'".format(name))
sys.exit(1)

db.cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart})

if __name__ == '__main__':
config()
56 changes: 56 additions & 0 deletions show/feature.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import click
from natsort import natsorted
from tabulate import tabulate

from utilities_common.cli import AbbreviationGroup, pass_db

#
# 'feature' group (show feature ...)
#
@click.group(cls=AbbreviationGroup, name='feature', invoke_without_command=False)
def feature():
"""Show feature status"""
pass

#
# 'status' subcommand (show feature status)
#
@feature.command('status', short_help="Show feature state")
@click.argument('feature_name', required=False)
@pass_db
def feature_status(db, feature_name):
header = ['Feature', 'State', 'AutoRestart']
body = []
feature_table = db.cfgdb.get_table('FEATURE')
if feature_name:
if feature_table and feature_table.has_key(feature_name):
body.append([feature_name, feature_table[feature_name]['state'], \
feature_table[feature_name]['auto_restart']])
else:
click.echo("Can not find feature {}".format(feature_name))
sys.exit(1)
else:
for key in natsorted(feature_table.keys()):
body.append([key, feature_table[key]['state'], feature_table[key]['auto_restart']])
click.echo(tabulate(body, header))

#
# 'autorestart' subcommand (show feature autorestart)
#
@feature.command('autorestart', short_help="Show auto-restart state for a feature")
@click.argument('feature_name', required=False)
@pass_db
def feature_autorestart(db, feature_name):
header = ['Feature', 'AutoRestart']
body = []
feature_table = db.cfgdb.get_table('FEATURE')
if feature_name:
if feature_table and feature_table.has_key(feature_name):
body.append([feature_name, feature_table[feature_name]['auto_restart']])
else:
click.echo("Can not find feature {}".format(feature_name))
sys.exit(1)
else:
for name in natsorted(feature_table.keys()):
body.append([name, feature_table[name]['auto_restart']])
click.echo(tabulate(body, header))
54 changes: 2 additions & 52 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from tabulate import tabulate
from utilities_common.db import Db

import feature
import mlnx

# Global Variables
Expand Down Expand Up @@ -559,7 +560,7 @@ def cli(ctx):

ctx.obj = Db()

pass_db = click.make_pass_decorator(Db, ensure=True)
cli.add_command(feature.feature)

#
# 'vrf' command ("show vrf")
Expand Down Expand Up @@ -3040,57 +3041,6 @@ def ztp(status, verbose):
cmd = cmd + " --verbose"
run_command(cmd, display_cmd=verbose)

#
# 'feature' group (show feature ...)
#
@cli.group(name='feature', invoke_without_command=False)
def feature():
"""Show feature status"""
pass

#
# 'status' subcommand (show feature status)
#
@feature.command('status', short_help="Show feature state")
@click.argument('feature_name', required=False)
@pass_db
def feature_status(db, feature_name):
header = ['Feature', 'State', 'AutoRestart']
body = []
feature_table = db.cfgdb.get_table('FEATURE')
if feature_name:
if feature_table and feature_table.has_key(feature_name):
body.append([feature_name, feature_table[feature_name]['state'], \
feature_table[feature_name]['auto_restart']])
else:
click.echo("Can not find feature {}".format(feature_name))
sys.exit(1)
else:
for key in natsorted(feature_table.keys()):
body.append([key, feature_table[key]['state'], feature_table[key]['auto_restart']])
click.echo(tabulate(body, header))

#
# 'autorestart' subcommand (show feature autorestart)
#
@feature.command('autorestart', short_help="Show auto-restart state for a feature")
@click.argument('feature_name', required=False)
@pass_db
def feature_autorestart(db, feature_name):
header = ['Feature', 'AutoRestart']
body = []
feature_table = db.cfgdb.get_table('FEATURE')
if feature_name:
if feature_table and feature_table.has_key(feature_name):
body.append([feature_name, feature_table[feature_name]['auto_restart']])
else:
click.echo("Can not find feature {}".format(feature_name))
sys.exit(1)
else:
for name in natsorted(feature_table.keys()):
body.append([name, feature_table[name]['auto_restart']])
click.echo(tabulate(body, header))

#
# 'vnet' command ("show vnet")
#
Expand Down
9 changes: 9 additions & 0 deletions tests/feature_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ def test_show_feature_status(self, get_cmd_module):
assert result.exit_code == 0
assert result.output == show_feature_status_output

def test_show_feature_status_abbrev_cmd(self, get_cmd_module):
(config, show) = get_cmd_module
runner = CliRunner()
result = runner.invoke(show.cli.commands["feature"], ["st"])
print(result.exit_code)
print(result.output)
assert result.exit_code == 0
assert result.output == show_feature_status_output

def test_show_bgp_feature_status(self, get_cmd_module):
(config, show) = get_cmd_module
runner = CliRunner()
Expand Down
43 changes: 43 additions & 0 deletions utilities_common/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import click

from utilities_common.db import Db

pass_db = click.make_pass_decorator(Db, ensure=True)

class AbbreviationGroup(click.Group):
"""This subclass of click.Group supports abbreviated subgroup/subcommand names
"""

def get_command(self, ctx, cmd_name):
# Try to get builtin commands as normal
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv

# Allow automatic abbreviation of the command. "status" for
# instance will match "st". We only allow that however if
# there is only one command.
# If there are multiple matches and the shortest one is the common prefix of all the matches, return
# the shortest one
matches = []
shortest = None
for x in self.list_commands(ctx):
if x.lower().startswith(cmd_name.lower()):
matches.append(x)
if not shortest:
shortest = x
elif len(shortest) > len(x):
shortest = x

if not matches:
return None
elif len(matches) == 1:
return click.Group.get_command(self, ctx, matches[0])
else:
for x in matches:
if not x.startswith(shortest):
break
else:
return click.Group.get_command(self, ctx, shortest)

ctx.fail('Too many matches: %s' % ', '.join(sorted(matches)))