Skip to content

Commit 3490d3a

Browse files
authored
Merge pull request sonic-net#22 from zhenggen-xu/sonic-cfg-mgmt-merge2
Sonic cfg mgmt merge2
2 parents 37bb34b + 625ea6b commit 3490d3a

31 files changed

+2971
-25
lines changed

config/main.py

+217-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?'])
3636

37+
SONIC_GENERATED_SERVICE_PATH = '/etc/sonic/generated_services.conf'
3738
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
3839
SYSLOG_IDENTIFIER = "config"
3940
PORT_STR = "Ethernet"
@@ -44,6 +45,7 @@
4445

4546
VLAN_SUB_INTERFACE_SEPARATOR = '.'
4647

48+
INIT_CFG_FILE = '/etc/sonic/init_cfg.json'
4749

4850
# ========================== Syslog wrappers ==========================
4951

@@ -521,6 +523,15 @@ def _get_platform():
521523
return tokens[1].strip()
522524
return ''
523525

526+
def _get_sonic_generated_services():
527+
if not os.path.isfile(SONIC_GENERATED_SERVICE_PATH):
528+
return None
529+
generated_services_list = []
530+
with open(SONIC_GENERATED_SERVICE_PATH) as generated_service_file:
531+
for line in generated_service_file:
532+
generated_services_list.append(line.rstrip('\n'))
533+
return None if not generated_services_list else generated_services_list
534+
524535
# Callback for confirmation prompt. Aborts if user enters "n"
525536
def _abort_if_false(ctx, param, value):
526537
if not value:
@@ -536,10 +547,18 @@ def _stop_services():
536547
'hostcfgd',
537548
'nat'
538549
]
550+
generated_services_list = _get_sonic_generated_services()
551+
552+
if generated_services_list is None:
553+
log_error("Failed to get generated services")
554+
return
555+
539556
if asic_type == 'mellanox' and 'pmon' in services_to_stop:
540557
services_to_stop.remove('pmon')
541558

542559
for service in services_to_stop:
560+
if service + '.service' not in generated_services_list:
561+
continue
543562
try:
544563
click.echo("Stopping service {} ...".format(service))
545564
run_command("systemctl stop {}".format(service))
@@ -567,7 +586,15 @@ def _reset_failed_services():
567586
'nat'
568587
]
569588

589+
generated_services_list = _get_sonic_generated_services()
590+
591+
if generated_services_list is None:
592+
log_error("Failed to get generated services")
593+
return
594+
570595
for service in services_to_reset:
596+
if service + '.service' not in generated_services_list:
597+
continue
571598
try:
572599
click.echo("Resetting failed status for service {} ...".format(service))
573600
run_command("systemctl reset-failed {}".format(service))
@@ -590,10 +617,18 @@ def _restart_services():
590617
'nat',
591618
'sflow',
592619
]
620+
generated_services_list = _get_sonic_generated_services()
621+
622+
if generated_services_list is None:
623+
log_error("Failed to get generated services")
624+
return
625+
593626
if asic_type == 'mellanox' and 'pmon' in services_to_restart:
594627
services_to_restart.remove('pmon')
595628

596629
for service in services_to_restart:
630+
if service + '.service' not in generated_services_list:
631+
continue
597632
try:
598633
click.echo("Restarting service {} ...".format(service))
599634
run_command("systemctl restart {}".format(service))
@@ -695,7 +730,11 @@ def reload(filename, yes, load_sysinfo, disable_validation):
695730
command = "{} -H -k {} --write-to-db".format(SONIC_CFGGEN_PATH, cfg_hwsku)
696731
run_command(command, display_cmd=True)
697732

698-
command = "{} -j {} --write-to-db".format(SONIC_CFGGEN_PATH, filename)
733+
if os.path.isfile(INIT_CFG_FILE):
734+
command = "{} -j {} -j {} --write-to-db".format(SONIC_CFGGEN_PATH, INIT_CFG_FILE, filename)
735+
else:
736+
command = "{} -j {} --write-to-db".format(SONIC_CFGGEN_PATH, filename)
737+
699738
run_command(command, display_cmd=True)
700739
client.set(config_db.INIT_INDICATOR, 1)
701740

@@ -709,7 +748,7 @@ def reload(filename, yes, load_sysinfo, disable_validation):
709748
_reset_failed_services()
710749
_restart_services()
711750

712-
@config.command()
751+
@config.command("load_mgmt_config")
713752
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
714753
expose_value=False, prompt='Reload mgmt config?')
715754
@click.argument('filename', default='/etc/sonic/device_desc.xml', type=click.Path(exists=True))
@@ -733,7 +772,7 @@ def load_mgmt_config(filename):
733772
run_command(command, display_cmd=True, ignore_error=True)
734773
click.echo("Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.")
735774

736-
@config.command()
775+
@config.command("load_minigraph")
737776
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
738777
expose_value=False, prompt='Reload config from minigraph?')
739778
def load_minigraph():
@@ -913,6 +952,91 @@ def remove(session_name):
913952
config_db.connect()
914953
config_db.set_entry("MIRROR_SESSION", session_name, None)
915954

955+
#
956+
# 'pfcwd' group ('config pfcwd ...')
957+
#
958+
@config.group()
959+
def pfcwd():
960+
"""Configure pfc watchdog """
961+
pass
962+
963+
@pfcwd.command()
964+
@click.option('--action', '-a', type=click.Choice(['drop', 'forward', 'alert']))
965+
@click.option('--restoration-time', '-r', type=click.IntRange(100, 60000))
966+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
967+
@click.argument('ports', nargs=-1)
968+
@click.argument('detection-time', type=click.IntRange(100, 5000))
969+
def start(action, restoration_time, ports, detection_time, verbose):
970+
"""
971+
Start PFC watchdog on port(s). To config all ports, use all as input.
972+
973+
Example:
974+
config pfcwd start --action drop ports all detection-time 400 --restoration-time 400
975+
"""
976+
cmd = "pfcwd start"
977+
978+
if action:
979+
cmd += " --action {}".format(action)
980+
981+
if ports:
982+
ports = set(ports) - set(['ports', 'detection-time'])
983+
cmd += " ports {}".format(' '.join(ports))
984+
985+
if detection_time:
986+
cmd += " detection-time {}".format(detection_time)
987+
988+
if restoration_time:
989+
cmd += " --restoration-time {}".format(restoration_time)
990+
991+
run_command(cmd, display_cmd=verbose)
992+
993+
@pfcwd.command()
994+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
995+
def stop(verbose):
996+
""" Stop PFC watchdog """
997+
998+
cmd = "pfcwd stop"
999+
1000+
run_command(cmd, display_cmd=verbose)
1001+
1002+
@pfcwd.command()
1003+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1004+
@click.argument('poll_interval', type=click.IntRange(100, 3000))
1005+
def interval(poll_interval, verbose):
1006+
""" Set PFC watchdog counter polling interval (ms) """
1007+
1008+
cmd = "pfcwd interval {}".format(poll_interval)
1009+
1010+
run_command(cmd, display_cmd=verbose)
1011+
1012+
@pfcwd.command()
1013+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1014+
@click.argument('counter_poll', type=click.Choice(['enable', 'disable']))
1015+
def counter_poll(counter_poll, verbose):
1016+
""" Enable/disable counter polling """
1017+
1018+
cmd = "pfcwd counter_poll {}".format(counter_poll)
1019+
1020+
run_command(cmd, display_cmd=verbose)
1021+
1022+
@pfcwd.command()
1023+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1024+
@click.argument('big_red_switch', type=click.Choice(['enable', 'disable']))
1025+
def big_red_switch(big_red_switch, verbose):
1026+
""" Enable/disable BIG_RED_SWITCH mode """
1027+
1028+
cmd = "pfcwd big_red_switch {}".format(big_red_switch)
1029+
1030+
run_command(cmd, display_cmd=verbose)
1031+
1032+
@pfcwd.command()
1033+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1034+
def start_default(verbose):
1035+
""" Start PFC WD by default configurations """
1036+
1037+
cmd = "pfcwd start_default"
1038+
1039+
run_command(cmd, display_cmd=verbose)
9161040

9171041
#
9181042
# 'qos' group ('config qos ...')
@@ -1086,6 +1210,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
10861210
db = ctx.obj['db']
10871211
vlan_name = 'Vlan{}'.format(vid)
10881212
vlan = db.get_entry('VLAN', vlan_name)
1213+
interface_table = db.get_table('INTERFACE')
10891214

10901215
if get_interface_naming_mode() == "alias":
10911216
interface_name = interface_alias_to_name(interface_name)
@@ -1105,6 +1230,10 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
11051230
else:
11061231
ctx.fail("{} is already a member of {}".format(interface_name,
11071232
vlan_name))
1233+
for entry in interface_table:
1234+
if (interface_name == entry[0]):
1235+
ctx.fail("{} is a L3 interface!".format(interface_name))
1236+
11081237
members.append(interface_name)
11091238
vlan['members'] = members
11101239
db.set_entry('VLAN', vlan_name, vlan)
@@ -1304,7 +1433,8 @@ def add_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip):
13041433
return
13051434
else:
13061435
dhcp_relay_dests.append(dhcp_relay_destination_ip)
1307-
db.set_entry('VLAN', vlan_name, {"dhcp_servers":dhcp_relay_dests})
1436+
vlan['dhcp_servers'] = dhcp_relay_dests
1437+
db.set_entry('VLAN', vlan_name, vlan)
13081438
click.echo("Added DHCP relay destination address {} to {}".format(dhcp_relay_destination_ip, vlan_name))
13091439
try:
13101440
click.echo("Restarting DHCP relay service...")
@@ -1329,7 +1459,11 @@ def del_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip):
13291459
dhcp_relay_dests = vlan.get('dhcp_servers', [])
13301460
if dhcp_relay_destination_ip in dhcp_relay_dests:
13311461
dhcp_relay_dests.remove(dhcp_relay_destination_ip)
1332-
db.set_entry('VLAN', vlan_name, {"dhcp_servers":dhcp_relay_dests})
1462+
if len(dhcp_relay_dests) == 0:
1463+
del vlan['dhcp_servers']
1464+
else:
1465+
vlan['dhcp_servers'] = dhcp_relay_dests
1466+
db.set_entry('VLAN', vlan_name, vlan)
13331467
click.echo("Removed DHCP relay destination address {} from {}".format(dhcp_relay_destination_ip, vlan_name))
13341468
try:
13351469
click.echo("Restarting DHCP relay service...")
@@ -2253,6 +2387,48 @@ def platform():
22532387
if asic_type == 'mellanox':
22542388
platform.add_command(mlnx.mlnx)
22552389

2390+
# 'firmware' subgroup ("config platform firmware ...")
2391+
@platform.group()
2392+
def firmware():
2393+
"""Firmware configuration tasks"""
2394+
pass
2395+
2396+
# 'install' subcommand ("config platform firmware install")
2397+
@firmware.command(
2398+
context_settings=dict(
2399+
ignore_unknown_options=True,
2400+
allow_extra_args=True
2401+
),
2402+
add_help_option=False
2403+
)
2404+
@click.argument('args', nargs=-1, type=click.UNPROCESSED)
2405+
def install(args):
2406+
"""Install platform firmware"""
2407+
cmd = "fwutil install {}".format(" ".join(args))
2408+
2409+
try:
2410+
subprocess.check_call(cmd, shell=True)
2411+
except subprocess.CalledProcessError as e:
2412+
sys.exit(e.returncode)
2413+
2414+
# 'update' subcommand ("config platform firmware update")
2415+
@firmware.command(
2416+
context_settings=dict(
2417+
ignore_unknown_options=True,
2418+
allow_extra_args=True
2419+
),
2420+
add_help_option=False
2421+
)
2422+
@click.argument('args', nargs=-1, type=click.UNPROCESSED)
2423+
def update(args):
2424+
"""Update platform firmware"""
2425+
cmd = "fwutil update {}".format(" ".join(args))
2426+
2427+
try:
2428+
subprocess.check_call(cmd, shell=True)
2429+
except subprocess.CalledProcessError as e:
2430+
sys.exit(e.returncode)
2431+
22562432
#
22572433
# 'watermark' group ("show watermark telemetry interval")
22582434
#
@@ -2732,5 +2908,41 @@ def feature_status(name, state):
27322908

27332909
config_db.mod_entry('FEATURE', name, {'status': state})
27342910

2911+
#
2912+
# 'container' group ('config container ...')
2913+
#
2914+
@config.group(name='container', invoke_without_command=False)
2915+
def container():
2916+
"""Modify configuration of containers"""
2917+
pass
2918+
2919+
#
2920+
# 'feature' group ('config container feature ...')
2921+
#
2922+
@container.group(name='feature', invoke_without_command=False)
2923+
def feature():
2924+
"""Modify configuration of container features"""
2925+
pass
2926+
2927+
#
2928+
# 'autorestart' subcommand ('config container feature autorestart ...')
2929+
#
2930+
@feature.command(name='autorestart', short_help="Configure the status of autorestart feature for specific container")
2931+
@click.argument('container_name', metavar='<container_name>', required=True)
2932+
@click.argument('autorestart_status', metavar='<autorestart_status>', required=True, type=click.Choice(["enabled", "disabled"]))
2933+
def autorestart(container_name, autorestart_status):
2934+
config_db = ConfigDBConnector()
2935+
config_db.connect()
2936+
container_feature_table = config_db.get_table('CONTAINER_FEATURE')
2937+
if not container_feature_table:
2938+
click.echo("Unable to retrieve container feature table from Config DB.")
2939+
return
2940+
2941+
if not container_feature_table.has_key(container_name):
2942+
click.echo("Unable to retrieve features for container '{}'".format(container_name))
2943+
return
2944+
2945+
config_db.mod_entry('CONTAINER_FEATURE', container_name, {'auto_restart': autorestart_status})
2946+
27352947
if __name__ == '__main__':
27362948
config()

config/nat.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ def add_basic(ctx, global_ip, local_ip, nat_type, twice_nat_id):
283283
ctx.fail("Given entry is overlapping with existing Dynamic entry !!")
284284

285285
if entryFound is False:
286-
counters_db = SonicV2Connector(host="127.0.0.1")
286+
counters_db = SonicV2Connector()
287287
counters_db.connect(counters_db.COUNTERS_DB)
288288
snat_entries = 0
289289
max_entries = 0
@@ -363,7 +363,7 @@ def add_tcp(ctx, global_ip, global_port, local_ip, local_port, nat_type, twice_n
363363
ctx.fail("Given entry is overlapping with existing NAT entry !!")
364364

365365
if entryFound is False:
366-
counters_db = SonicV2Connector(host="127.0.0.1")
366+
counters_db = SonicV2Connector()
367367
counters_db.connect(counters_db.COUNTERS_DB)
368368
snat_entries = 0
369369
max_entries = 0
@@ -443,7 +443,7 @@ def add_udp(ctx, global_ip, global_port, local_ip, local_port, nat_type, twice_n
443443
ctx.fail("Given entry is overlapping with existing NAT entry !!")
444444

445445
if entryFound is False:
446-
counters_db = SonicV2Connector(host="127.0.0.1")
446+
counters_db = SonicV2Connector()
447447
counters_db.connect(counters_db.COUNTERS_DB)
448448
snat_entries = 0
449449
max_entries = 0

data/etc/bash_completion.d/fwutil

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
_fwutil_completion() {
2+
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
3+
COMP_CWORD=$COMP_CWORD \
4+
_FWUTIL_COMPLETE=complete $1 ) )
5+
return 0
6+
}
7+
8+
complete -F _fwutil_completion -o default fwutil;
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
_pddf_fanutil_completion() {
2+
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
3+
COMP_CWORD=$COMP_CWORD \
4+
_PDDF_FANUTIL_COMPLETE=complete $1 ) )
5+
return 0
6+
}
7+
8+
complete -F _pddf_fanutil_completion -o default pddf_fanutil;
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
_pddf_ledutil_completion() {
2+
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
3+
COMP_CWORD=$COMP_CWORD \
4+
_PDDF_LEDUTIL_COMPLETE=complete $1 ) )
5+
return 0
6+
}
7+
8+
complete -F _pddf_ledutil_completion -o default pddf_ledutil;

0 commit comments

Comments
 (0)