Skip to content
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
146 changes: 105 additions & 41 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3812,92 +3812,156 @@ def warm_restart(ctx, redis_unix_socket_path):
# Note: redis_unix_socket_path is a path string, and the ground truth is now from database_config.json.
# We only use it as a bool indicator on either unix_socket_path or tcp port
use_unix_socket_path = bool(redis_unix_socket_path)
config_db = ConfigDBConnector(use_unix_socket_path=use_unix_socket_path)
config_db.connect(wait_for_init=False)

# warm restart enable/disable config is put in stateDB, not persistent across cold reboot, not saved to config_DB.json file
state_db = SonicV2Connector(use_unix_socket_path=use_unix_socket_path)
state_db.connect(state_db.STATE_DB, False)
TABLE_NAME_SEPARATOR = '|'
prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR
ctx.obj = {'db': config_db, 'state_db': state_db, 'prefix': prefix}
ctx.obj = {'prefix': prefix}

asic_namespaces = multi_asic.get_namespace_list()
all_namespaces = asic_namespaces
if multi_asic.is_multi_asic():
all_namespaces = [multi_asic_util.constants.DEFAULT_NAMESPACE] + asic_namespaces
ctx.obj["all_namespaces"] = all_namespaces
ctx.obj["asic_namespaces"] = asic_namespaces
ctx.obj["state_db"] = {}
ctx.obj["config_db"] = {}
for namespace in all_namespaces:
config_db = ConfigDBConnector(namespace=namespace, use_unix_socket_path=use_unix_socket_path)
config_db.connect(wait_for_init=False)
state_db = SonicV2Connector(namespace=namespace, use_unix_socket_path=use_unix_socket_path)
state_db.connect(state_db.STATE_DB, False)
ctx.obj["state_db"][namespace] = state_db
ctx.obj["config_db"][namespace] = config_db


@warm_restart.command('enable')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('module', metavar='<module>', default='system', required=False)
@click.pass_context
def warm_restart_enable(ctx, module):
state_db = ctx.obj['state_db']
config_db = ctx.obj['db']
def warm_restart_enable(ctx, namespace, module):
if namespace is not None:
if namespace not in ctx.obj["all_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["all_namespaces"]

config_db = ctx.obj["config_db"][multi_asic_util.constants.DEFAULT_NAMESPACE]
feature_table = config_db.get_table('FEATURE')
if module != 'system' and module not in feature_table:
sys.exit('Feature {} is unknown'.format(module))
prefix = ctx.obj['prefix']
_hash = '{}{}'.format(prefix, module)
state_db.set(state_db.STATE_DB, _hash, 'enable', 'true')
state_db.close(state_db.STATE_DB)

for namespace in namespaces:
state_db = ctx.obj["state_db"][namespace]
state_db.set(state_db.STATE_DB, _hash, 'enable', 'true')
state_db.close(state_db.STATE_DB)


@warm_restart.command('disable')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('module', metavar='<module>', default='system', required=False)
@click.pass_context
def warm_restart_disable(ctx, module):
state_db = ctx.obj['state_db']
config_db = ctx.obj['db']
def warm_restart_disable(ctx, namespace, module):
if namespace is not None:
if namespace not in ctx.obj["all_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["all_namespaces"]

config_db = ctx.obj["config_db"][multi_asic_util.constants.DEFAULT_NAMESPACE]
feature_table = config_db.get_table('FEATURE')
if module != 'system' and module not in feature_table:
sys.exit('Feature {} is unknown'.format(module))
prefix = ctx.obj['prefix']
_hash = '{}{}'.format(prefix, module)
state_db.set(state_db.STATE_DB, _hash, 'enable', 'false')
state_db.close(state_db.STATE_DB)

for namespace in namespaces:
state_db = ctx.obj["state_db"][namespace]
state_db.set(state_db.STATE_DB, _hash, 'enable', 'false')
state_db.close(state_db.STATE_DB)


@warm_restart.command('neighsyncd_timer')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('seconds', metavar='<seconds>', required=True, type=int)
@click.pass_context
def warm_restart_neighsyncd_timer(ctx, seconds):
db = ValidatedConfigDBConnector(ctx.obj['db'])
def warm_restart_neighsyncd_timer(ctx, namespace, seconds):
if namespace is not None:
if namespace not in ctx.obj["asic_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["asic_namespaces"]

if ADHOC_VALIDATION:
if seconds not in range(1, 9999):
ctx.fail("neighsyncd warm restart timer must be in range 1-9999")
try:
db.mod_entry('WARM_RESTART', 'swss', {'neighsyncd_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))

for namespace in namespaces:
db = ValidatedConfigDBConnector(ctx.obj["config_db"][namespace])
try:
db.mod_entry('WARM_RESTART', 'swss', {'neighsyncd_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))


@warm_restart.command('bgp_timer')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('seconds', metavar='<seconds>', required=True, type=int)
@click.pass_context
def warm_restart_bgp_timer(ctx, seconds):
db = ValidatedConfigDBConnector(ctx.obj['db'])
def warm_restart_bgp_timer(ctx, namespace, seconds):
if namespace is not None:
if namespace not in ctx.obj["asic_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["asic_namespaces"]

if ADHOC_VALIDATION:
if seconds not in range(1, 3600):
ctx.fail("bgp warm restart timer must be in range 1-3600")
try:
db.mod_entry('WARM_RESTART', 'bgp', {'bgp_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))

for namespace in namespaces:
db = ValidatedConfigDBConnector(ctx.obj["config_db"][namespace])
try:
db.mod_entry('WARM_RESTART', 'bgp', {'bgp_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))


@warm_restart.command('teamsyncd_timer')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('seconds', metavar='<seconds>', required=True, type=int)
@click.pass_context
def warm_restart_teamsyncd_timer(ctx, seconds):
db = ValidatedConfigDBConnector(ctx.obj['db'])
def warm_restart_teamsyncd_timer(ctx, namespace, seconds):
if namespace is not None:
if namespace not in ctx.obj["asic_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["asic_namespaces"]

if ADHOC_VALIDATION:
if seconds not in range(1, 3600):
ctx.fail("teamsyncd warm restart timer must be in range 1-3600")
try:
db.mod_entry('WARM_RESTART', 'teamd', {'teamsyncd_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))

for namespace in namespaces:
db = ValidatedConfigDBConnector(ctx.obj["config_db"][namespace])
try:
db.mod_entry('WARM_RESTART', 'teamd', {'teamsyncd_timer': seconds})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))


@warm_restart.command('bgp_eoiu')
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.argument('enable', metavar='<enable>', default='true', required=False, type=click.Choice(["true", "false"]))
@click.pass_context
def warm_restart_bgp_eoiu(ctx, enable):
db = ValidatedConfigDBConnector(ctx.obj['db'])
try:
db.mod_entry('WARM_RESTART', 'bgp', {'bgp_eoiu': enable})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
def warm_restart_bgp_eoiu(ctx, namespace, enable):
if namespace is not None:
if namespace not in ctx.obj["asic_namespaces"]:
raise click.UsageError("Invalid namespace: {}".format(namespace))
namespaces = [namespace] if namespace else ctx.obj["asic_namespaces"]

for namespace in namespaces:
db = ValidatedConfigDBConnector(ctx.obj["config_db"][namespace])
try:
db.mod_entry('WARM_RESTART', 'bgp', {'bgp_eoiu': enable})
except ValueError as e:
ctx.fail("Invalid ConfigDB. Error: {}".format(e))


def vrf_add_management_vrf(config_db):
"""Enable management vrf in config DB"""
Expand Down
63 changes: 56 additions & 7 deletions show/warm_restart.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import click
import utilities_common.cli as clicommon
import utilities_common.multi_asic as multi_asic_util
from sonic_py_common import multi_asic
from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector
from tabulate import tabulate

Expand All @@ -11,14 +13,38 @@ def warm_restart():


@warm_restart.command()
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection')
def state(redis_unix_socket_path):
def state(namespace, redis_unix_socket_path):
"""Show warm restart state"""
kwargs = {}

if redis_unix_socket_path:
kwargs['unix_socket_path'] = redis_unix_socket_path
click.secho(
"Warning: '-s|--redis-unix-socket-path' has no effect and is left for compatibility",
fg="red", err=True)

if namespace and namespace not in multi_asic.get_namespace_list():
raise click.UsageError("Invalid namespace: {}".format(namespace))

asic_namespaces = multi_asic.get_namespace_list()
all_namespaces = asic_namespaces
if multi_asic.is_multi_asic():
all_namespaces = [multi_asic_util.constants.DEFAULT_NAMESPACE] + asic_namespaces
if namespace is not None and namespace not in asic_namespaces:
raise click.UsageError("Invalid namespace: {}".format(namespace))

namespaces = [namespace] if namespace else all_namespaces

for namespace in namespaces:
if len(namespaces) > 1:
namespace_str = namespace or "global"
click.echo(f"\nFor namespace {namespace_str}:\n")

show_warm_restart_state_for_namespace(namespace)

db = SonicV2Connector(host='127.0.0.1')

def show_warm_restart_state_for_namespace(namespace):
db = SonicV2Connector(namespace=namespace)
db.connect(db.STATE_DB, False) # Make one attempt only

TABLE_NAME_SEPARATOR = '|'
Expand Down Expand Up @@ -53,19 +79,42 @@ def remove_prefix(text, prefix):


@warm_restart.command()
@click.option('--namespace', '-n', 'namespace', default=None, help='Namespace name')
@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection')
def config(redis_unix_socket_path):
def config(namespace, redis_unix_socket_path):
"""Show warm restart config"""
kwargs = {}
if redis_unix_socket_path:
kwargs['unix_socket_path'] = redis_unix_socket_path
config_db = ConfigDBConnector(**kwargs)

if namespace is not None and redis_unix_socket_path:
raise click.UsageError("Cannot specify both namespace and redis unix socket path")

asic_namespaces = multi_asic.get_namespace_list()
all_namespaces = asic_namespaces
if multi_asic.is_multi_asic():
all_namespaces = [multi_asic_util.constants.DEFAULT_NAMESPACE] + asic_namespaces
if namespace is not None and namespace not in asic_namespaces:
raise click.UsageError("Invalid namespace: {}".format(namespace))

namespaces = [namespace] if namespace else all_namespaces

for namespace in namespaces:
if len(namespaces) > 1:
namespace_str = namespace or "global"
click.echo(f"\nFor namespace {namespace_str}:\n")

show_warm_restart_config_for_namespace(namespace, **kwargs)


def show_warm_restart_config_for_namespace(namespace, **kwargs):
config_db = ConfigDBConnector(namespace=namespace, **kwargs)
config_db.connect(wait_for_init=False)
data = config_db.get_table('WARM_RESTART')
# Python dictionary keys() Method
keys = list(data.keys())

state_db = SonicV2Connector(host='127.0.0.1')
state_db = SonicV2Connector(namespace=namespace)
state_db.connect(state_db.STATE_DB, False) # Make one attempt only
TABLE_NAME_SEPARATOR = '|'
prefix = 'WARM_RESTART_ENABLE_TABLE' + TABLE_NAME_SEPARATOR
Expand Down
14 changes: 7 additions & 7 deletions tests/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3015,7 +3015,7 @@ def test_warm_restart_neighsyncd_timer_yang_validation(self):
config.ADHOC_VALIDATION = False
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["neighsyncd_timer"], ["2000"], obj=obj)
print(result.exit_code)
Expand All @@ -3027,7 +3027,7 @@ def test_warm_restart_neighsyncd_timer(self):
config.ADHOC_VALIDATION = True
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["neighsyncd_timer"], ["0"], obj=obj)
print(result.exit_code)
Expand All @@ -3041,7 +3041,7 @@ def test_warm_restart_bgp_timer_yang_validation(self):
config.ADHOC_VALIDATION = False
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["bgp_timer"], ["2000"], obj=obj)
print(result.exit_code)
Expand All @@ -3053,7 +3053,7 @@ def test_warm_restart_bgp_timer(self):
config.ADHOC_VALIDATION = True
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["bgp_timer"], ["0"], obj=obj)
print(result.exit_code)
Expand All @@ -3067,7 +3067,7 @@ def test_warm_restart_teamsyncd_timer_yang_validation(self):
config.ADHOC_VALIDATION = False
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["teamsyncd_timer"], ["2000"], obj=obj)
print(result.exit_code)
Expand All @@ -3079,7 +3079,7 @@ def test_warm_restart_teamsyncd_timer(self):
config.ADHOC_VALIDATION = True
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["teamsyncd_timer"], ["0"], obj=obj)
print(result.exit_code)
Expand All @@ -3093,7 +3093,7 @@ def test_warm_restart_bgp_eoiu_yang_validation(self):
config.ADHOC_VALIDATION = False
runner = CliRunner()
db = Db()
obj = {'db':db.cfgdb}
obj = {'config_db': {'': db.cfgdb}, 'asic_namespaces': ['']}

result = runner.invoke(config.config.commands["warm_restart"].commands["bgp_eoiu"], ["true"], obj=obj)
print(result.exit_code)
Expand Down
Loading
Loading