Skip to content

Commit ed3d7cb

Browse files
authored
[cli]: pass db connector as click context (sonic-net#1029)
it is better not let every command to have its own connector and connect to db. it is also not good to have a global db variable. Here, the idea is to have a single db connector and pass the connector as a click context Signed-off-by: Guohan Lu <[email protected]>
1 parent e17383a commit ed3d7cb

6 files changed

Lines changed: 70 additions & 50 deletions

File tree

config/main.py

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from config_mgmt import ConfigMgmtDPB
2020
from utilities_common.intf_filter import parse_interface_in_filter
2121
from utilities_common.util_base import UtilHelper
22+
from utilities_common.db import Db
2223
from portconfig import get_child_ports, get_port_config_file_name
2324

2425
import aaa
@@ -50,7 +51,6 @@
5051
CFG_LOOPBACK_NO="<0-999>"
5152

5253
asic_type = None
53-
config_db = None
5454

5555
# ========================== Syslog wrappers ==========================
5656

@@ -691,7 +691,7 @@ def _abort_if_false(ctx, param, value):
691691
ctx.abort()
692692

693693

694-
def _get_disabled_services_list():
694+
def _get_disabled_services_list(config_db):
695695
disabled_services_list = []
696696

697697
feature_table = config_db.get_table('FEATURE')
@@ -713,7 +713,7 @@ def _get_disabled_services_list():
713713

714714
return disabled_services_list
715715

716-
def _stop_services():
716+
def _stop_services(config_db):
717717
# This list is order-dependent. Please add services in the order they should be stopped
718718
# on Mellanox platform pmon is stopped by syncd
719719
services_to_stop = [
@@ -730,7 +730,7 @@ def _stop_services():
730730
if asic_type == 'mellanox' and 'pmon' in services_to_stop:
731731
services_to_stop.remove('pmon')
732732

733-
disabled_services = _get_disabled_services_list()
733+
disabled_services = _get_disabled_services_list(config_db)
734734

735735
for service in disabled_services:
736736
if service in services_to_stop:
@@ -739,7 +739,7 @@ def _stop_services():
739739
execute_systemctl(services_to_stop, SYSTEMCTL_ACTION_STOP)
740740

741741

742-
def _reset_failed_services():
742+
def _reset_failed_services(config_db):
743743
# This list is order-independent. Please keep list in alphabetical order
744744
services_to_reset = [
745745
'bgp',
@@ -762,7 +762,7 @@ def _reset_failed_services():
762762
'telemetry'
763763
]
764764

765-
disabled_services = _get_disabled_services_list()
765+
disabled_services = _get_disabled_services_list(config_db)
766766

767767
for service in disabled_services:
768768
if service in services_to_reset:
@@ -771,7 +771,7 @@ def _reset_failed_services():
771771
execute_systemctl(services_to_reset, SYSTEMCTL_ACTION_RESET_FAILED)
772772

773773

774-
def _restart_services():
774+
def _restart_services(config_db):
775775
# This list is order-dependent. Please add services in the order they should be started
776776
# on Mellanox platform pmon is started by syncd
777777
services_to_restart = [
@@ -790,7 +790,7 @@ def _restart_services():
790790
'telemetry'
791791
]
792792

793-
disabled_services = _get_disabled_services_list()
793+
disabled_services = _get_disabled_services_list(config_db)
794794

795795
for service in disabled_services:
796796
if service in services_to_restart:
@@ -908,7 +908,8 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port,
908908

909909
# This is our main entrypoint - the main 'config' command
910910
@click.group(cls=AbbreviationGroup, context_settings=CONTEXT_SETTINGS)
911-
def config():
911+
@click.pass_context
912+
def config(ctx):
912913
"""SONiC command line - 'config' command"""
913914
#
914915
# Load asic_type for further use
@@ -932,10 +933,9 @@ def config():
932933

933934
SonicDBConfig.load_sonic_global_db_config()
934935

935-
global config_db
936+
ctx.obj = Db()
936937

937-
config_db = ConfigDBConnector()
938-
config_db.connect()
938+
pass_db = click.make_pass_decorator(Db, ensure=True)
939939

940940
config.add_command(aaa.aaa)
941941
config.add_command(aaa.tacacs)
@@ -1060,7 +1060,8 @@ def load(filename, yes):
10601060
@click.option('-l', '--load-sysinfo', is_flag=True, help='load system default information (mac, portmap etc) first.')
10611061
@click.option('-n', '--no_service_restart', default=False, is_flag=True, help='Do not restart docker services')
10621062
@click.argument('filename', required=False)
1063-
def reload(filename, yes, load_sysinfo, no_service_restart):
1063+
@pass_db
1064+
def reload(db, filename, yes, load_sysinfo, no_service_restart):
10641065
"""Clear current configuration and import a previous saved config DB dump file.
10651066
<filename> : Names of configuration file(s) to load, separated by comma with no spaces in between
10661067
"""
@@ -1102,7 +1103,7 @@ def reload(filename, yes, load_sysinfo, no_service_restart):
11021103
#Stop services before config push
11031104
if not no_service_restart:
11041105
log_info("'reload' stopping services...")
1105-
_stop_services()
1106+
_stop_services(db.cfgdb)
11061107

11071108
""" In Single AISC platforms we have single DB service. In multi-ASIC platforms we have a global DB
11081109
service running in the host + DB services running in each ASIC namespace created per ASIC.
@@ -1175,9 +1176,9 @@ def reload(filename, yes, load_sysinfo, no_service_restart):
11751176
# We first run "systemctl reset-failed" to remove the "failed"
11761177
# status from all services before we attempt to restart them
11771178
if not no_service_restart:
1178-
_reset_failed_services()
1179+
_reset_failed_services(db.cfgdb)
11791180
log_info("'reload' restarting services...")
1180-
_restart_services()
1181+
_restart_services(db.cfgdb)
11811182

11821183
@config.command("load_mgmt_config")
11831184
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
@@ -1208,14 +1209,15 @@ def load_mgmt_config(filename):
12081209
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
12091210
expose_value=False, prompt='Reload config from minigraph?')
12101211
@click.option('-n', '--no_service_restart', default=False, is_flag=True, help='Do not restart docker services')
1211-
def load_minigraph(no_service_restart):
1212+
@pass_db
1213+
def load_minigraph(db, no_service_restart):
12121214
"""Reconfigure based on minigraph."""
12131215
log_info("'load_minigraph' executing...")
12141216

12151217
#Stop services before config push
12161218
if not no_service_restart:
12171219
log_info("'load_minigraph' stopping services...")
1218-
_stop_services()
1220+
_stop_services(db.cfgdb)
12191221

12201222
# For Single Asic platform the namespace list has the empty string
12211223
# for mulit Asic platform the empty string to generate the config
@@ -1269,10 +1271,10 @@ def load_minigraph(no_service_restart):
12691271
# We first run "systemctl reset-failed" to remove the "failed"
12701272
# status from all services before we attempt to restart them
12711273
if not no_service_restart:
1272-
_reset_failed_services()
1274+
_reset_failed_services(db.cfgdb)
12731275
#FIXME: After config DB daemon is implemented, we'll no longer need to restart every service.
12741276
log_info("'load_minigraph' restarting services...")
1275-
_restart_services()
1277+
_restart_services(db.cfgdb)
12761278
click.echo("Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.")
12771279

12781280

@@ -3810,25 +3812,27 @@ def feature():
38103812
@feature.command('state', short_help="Enable/disable a feature")
38113813
@click.argument('name', metavar='<feature-name>', required=True)
38123814
@click.argument('state', metavar='<state>', required=True, type=click.Choice(["enabled", "disabled"]))
3813-
def feature_state(name, state):
3815+
@pass_db
3816+
def feature_state(db, name, state):
38143817
"""Enable/disable a feature"""
3815-
state_data = config_db.get_entry('FEATURE', name)
3818+
state_data = db.cfgdb.get_entry('FEATURE', name)
38163819

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

3821-
config_db.mod_entry('FEATURE', name, {'state': state})
3824+
db.cfgdb.mod_entry('FEATURE', name, {'state': state})
38223825

38233826
#
38243827
# 'autorestart' command ('config feature autorestart ...')
38253828
#
38263829
@feature.command(name='autorestart', short_help="Enable/disable autosrestart of a feature")
38273830
@click.argument('name', metavar='<feature-name>', required=True)
38283831
@click.argument('autorestart', metavar='<autorestart>', required=True, type=click.Choice(["enabled", "disabled"]))
3829-
def feature_autorestart(name, autorestart):
3832+
@pass_db
3833+
def feature_autorestart(db, name, autorestart):
38303834
"""Enable/disable autorestart of a feature"""
3831-
feature_table = config_db.get_table('FEATURE')
3835+
feature_table = db.cfgdb.get_table('FEATURE')
38323836
if not feature_table:
38333837
click.echo("Unable to retrieve feature table from Config DB.")
38343838
sys.exit(1)
@@ -3837,7 +3841,7 @@ def feature_autorestart(name, autorestart):
38373841
click.echo("Unable to retrieve feature '{}'".format(name))
38383842
sys.exit(1)
38393843

3840-
config_db.mod_entry('FEATURE', name, {'auto_restart': autorestart})
3844+
db.cfgdb.mod_entry('FEATURE', name, {'auto_restart': autorestart})
38413845

38423846
if __name__ == '__main__':
38433847
config()

show/main.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from swsssdk import ConfigDBConnector
2020
from swsssdk import SonicV2Connector
2121
from portconfig import get_child_ports
22+
from utilities_common.db import Db
2223

2324
import mlnx
2425

@@ -31,8 +32,6 @@
3132

3233
VLAN_SUB_INTERFACE_SEPARATOR = '.'
3334

34-
config_db = None
35-
3635
try:
3736
# noinspection PyPep8Naming
3837
import ConfigParser as configparser
@@ -557,12 +556,13 @@ def get_bgp_neighbor_ip_to_name(ip, static_neighbors, dynamic_neighbors):
557556
# This is our entrypoint - the main "show" command
558557
# TODO: Consider changing function name to 'show' for better understandability
559558
@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS)
560-
def cli():
559+
@click.pass_context
560+
def cli(ctx):
561561
"""SONiC command line - 'show' command"""
562-
global config_db
563562

564-
config_db = ConfigDBConnector()
565-
config_db.connect()
563+
ctx.obj = Db()
564+
565+
pass_db = click.make_pass_decorator(Db, ensure=True)
566566

567567
#
568568
# 'vrf' command ("show vrf")
@@ -3064,14 +3064,15 @@ def feature():
30643064
pass
30653065

30663066
#
3067-
# 'state' subcommand (show feature status)
3067+
# 'status' subcommand (show feature status)
30683068
#
30693069
@feature.command('status', short_help="Show feature state")
30703070
@click.argument('feature_name', required=False)
3071-
def autorestart(feature_name):
3071+
@pass_db
3072+
def feature_status(db, feature_name):
30723073
header = ['Feature', 'State', 'AutoRestart']
30733074
body = []
3074-
feature_table = config_db.get_table('FEATURE')
3075+
feature_table = db.cfgdb.get_table('FEATURE')
30753076
if feature_name:
30763077
if feature_table and feature_table.has_key(feature_name):
30773078
body.append([feature_name, feature_table[feature_name]['state'], \
@@ -3089,10 +3090,11 @@ def autorestart(feature_name):
30893090
#
30903091
@feature.command('autorestart', short_help="Show auto-restart state for a feature")
30913092
@click.argument('feature_name', required=False)
3092-
def autorestart(feature_name):
3093+
@pass_db
3094+
def feature_autorestart(db, feature_name):
30933095
header = ['Feature', 'AutoRestart']
30943096
body = []
3095-
feature_table = config_db.get_table('FEATURE')
3097+
feature_table = db.cfgdb.get_table('FEATURE')
30963098
if feature_name:
30973099
if feature_table and feature_table.has_key(feature_name):
30983100
body.append([feature_name, feature_table[feature_name]['auto_restart']])

tests/config_test.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import traceback
2+
13
from click.testing import CliRunner
24

5+
from utilities_common.db import Db
6+
37
load_minigraph_command_output="""\
48
Executing stop of service telemetry...
59
Executing stop of service swss...
@@ -52,16 +56,20 @@ def test_load_minigraph(self, get_cmd_module, setup_single_broacom_asic):
5256
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"])
5357
print result.exit_code
5458
print result.output
59+
traceback.print_tb(result.exc_info[2])
5560
assert result.exit_code == 0
5661
assert "\n".join([ l.rstrip() for l in result.output.split('\n')]) == load_minigraph_command_output
5762

5863
def test_load_minigraph_with_disabled_telemetry(self, get_cmd_module, setup_single_broacom_asic):
5964
(config, show) = get_cmd_module
65+
db = Db()
6066
runner = CliRunner()
61-
runner.invoke(config.config.commands["feature"].commands["state"], ["telemetry", "disabled"])
62-
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["telemetry"])
67+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["telemetry", "disabled"], obj=db)
68+
assert result.exit_code == 0
69+
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["telemetry"], obj=db)
6370
print result.output
64-
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"])
71+
assert result.exit_code == 0
72+
result = runner.invoke(config.config.commands["load_minigraph"], ["-y"], obj=db)
6573
print result.exit_code
6674
print result.output
6775
assert result.exit_code == 0

tests/conftest.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ def get_cmd_module():
5858
import config.main as config
5959
import show.main as show
6060

61-
config_db = ConfigDBConnector()
62-
config_db.connect()
63-
64-
config.config_db = config_db
65-
show.config_db = config_db
66-
6761
config.run_command = _dummy_run_command
6862

6963
return (config, show)

tests/feature_test.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from click.testing import CliRunner
22

3+
from utilities_common.db import Db
4+
35
show_feature_status_output="""\
46
Feature State AutoRestart
57
---------- -------- -------------
@@ -122,22 +124,26 @@ def test_show_unknown_autorestart_status(self, get_cmd_module):
122124

123125
def test_config_bgp_feature_state(self, get_cmd_module):
124126
(config, show) = get_cmd_module
127+
db = Db()
125128
runner = CliRunner()
126-
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"])
129+
result = runner.invoke(config.config.commands["feature"].commands["state"], ["bgp", "disabled"], obj=db)
127130
print(result.exit_code)
128131
print(result.output)
129-
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"])
132+
assert result.exit_code == 0
133+
result = runner.invoke(show.cli.commands["feature"].commands["status"], ["bgp"], obj=db)
130134
print(result.output)
131135
assert result.exit_code == 0
132136
assert result.output == show_feature_bgp_disabled_status_output
133137

134138
def test_config_bgp_autorestart(self, get_cmd_module):
135139
(config, show) = get_cmd_module
140+
db = Db()
136141
runner = CliRunner()
137-
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"])
142+
result = runner.invoke(config.config.commands["feature"].commands["autorestart"], ["bgp", "disabled"], obj=db)
138143
print(result.exit_code)
139144
print(result.output)
140-
result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"])
145+
assert result.exit_code == 0
146+
result = runner.invoke(show.cli.commands["feature"].commands["autorestart"], ["bgp"], obj=db)
141147
print(result.output)
142148
assert result.exit_code == 0
143149
assert result.output == show_feature_bgp_disabled_autorestart_output

utilities_common/db.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from swsssdk import ConfigDBConnector
2+
3+
class Db(object):
4+
def __init__(self):
5+
self.cfgdb = ConfigDBConnector()
6+
self.cfgdb.connect()

0 commit comments

Comments
 (0)