34
34
35
35
CONTEXT_SETTINGS = dict (help_option_names = ['-h' , '--help' , '-?' ])
36
36
37
+ SONIC_GENERATED_SERVICE_PATH = '/etc/sonic/generated_services.conf'
37
38
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
38
39
SYSLOG_IDENTIFIER = "config"
39
40
PORT_STR = "Ethernet"
44
45
45
46
VLAN_SUB_INTERFACE_SEPARATOR = '.'
46
47
48
+ INIT_CFG_FILE = '/etc/sonic/init_cfg.json'
47
49
48
50
# ========================== Syslog wrappers ==========================
49
51
@@ -521,6 +523,15 @@ def _get_platform():
521
523
return tokens [1 ].strip ()
522
524
return ''
523
525
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
+
524
535
# Callback for confirmation prompt. Aborts if user enters "n"
525
536
def _abort_if_false (ctx , param , value ):
526
537
if not value :
@@ -536,10 +547,18 @@ def _stop_services():
536
547
'hostcfgd' ,
537
548
'nat'
538
549
]
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
+
539
556
if asic_type == 'mellanox' and 'pmon' in services_to_stop :
540
557
services_to_stop .remove ('pmon' )
541
558
542
559
for service in services_to_stop :
560
+ if service + '.service' not in generated_services_list :
561
+ continue
543
562
try :
544
563
click .echo ("Stopping service {} ..." .format (service ))
545
564
run_command ("systemctl stop {}" .format (service ))
@@ -567,7 +586,15 @@ def _reset_failed_services():
567
586
'nat'
568
587
]
569
588
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
+
570
595
for service in services_to_reset :
596
+ if service + '.service' not in generated_services_list :
597
+ continue
571
598
try :
572
599
click .echo ("Resetting failed status for service {} ..." .format (service ))
573
600
run_command ("systemctl reset-failed {}" .format (service ))
@@ -590,10 +617,18 @@ def _restart_services():
590
617
'nat' ,
591
618
'sflow' ,
592
619
]
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
+
593
626
if asic_type == 'mellanox' and 'pmon' in services_to_restart :
594
627
services_to_restart .remove ('pmon' )
595
628
596
629
for service in services_to_restart :
630
+ if service + '.service' not in generated_services_list :
631
+ continue
597
632
try :
598
633
click .echo ("Restarting service {} ..." .format (service ))
599
634
run_command ("systemctl restart {}" .format (service ))
@@ -695,7 +730,11 @@ def reload(filename, yes, load_sysinfo, disable_validation):
695
730
command = "{} -H -k {} --write-to-db" .format (SONIC_CFGGEN_PATH , cfg_hwsku )
696
731
run_command (command , display_cmd = True )
697
732
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
+
699
738
run_command (command , display_cmd = True )
700
739
client .set (config_db .INIT_INDICATOR , 1 )
701
740
@@ -709,7 +748,7 @@ def reload(filename, yes, load_sysinfo, disable_validation):
709
748
_reset_failed_services ()
710
749
_restart_services ()
711
750
712
- @config .command ()
751
+ @config .command ("load_mgmt_config" )
713
752
@click .option ('-y' , '--yes' , is_flag = True , callback = _abort_if_false ,
714
753
expose_value = False , prompt = 'Reload mgmt config?' )
715
754
@click .argument ('filename' , default = '/etc/sonic/device_desc.xml' , type = click .Path (exists = True ))
@@ -733,7 +772,7 @@ def load_mgmt_config(filename):
733
772
run_command (command , display_cmd = True , ignore_error = True )
734
773
click .echo ("Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`." )
735
774
736
- @config .command ()
775
+ @config .command ("load_minigraph" )
737
776
@click .option ('-y' , '--yes' , is_flag = True , callback = _abort_if_false ,
738
777
expose_value = False , prompt = 'Reload config from minigraph?' )
739
778
def load_minigraph ():
@@ -913,6 +952,91 @@ def remove(session_name):
913
952
config_db .connect ()
914
953
config_db .set_entry ("MIRROR_SESSION" , session_name , None )
915
954
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 )
916
1040
917
1041
#
918
1042
# 'qos' group ('config qos ...')
@@ -1086,6 +1210,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
1086
1210
db = ctx .obj ['db' ]
1087
1211
vlan_name = 'Vlan{}' .format (vid )
1088
1212
vlan = db .get_entry ('VLAN' , vlan_name )
1213
+ interface_table = db .get_table ('INTERFACE' )
1089
1214
1090
1215
if get_interface_naming_mode () == "alias" :
1091
1216
interface_name = interface_alias_to_name (interface_name )
@@ -1105,6 +1230,10 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
1105
1230
else :
1106
1231
ctx .fail ("{} is already a member of {}" .format (interface_name ,
1107
1232
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
+
1108
1237
members .append (interface_name )
1109
1238
vlan ['members' ] = members
1110
1239
db .set_entry ('VLAN' , vlan_name , vlan )
@@ -1304,7 +1433,8 @@ def add_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip):
1304
1433
return
1305
1434
else :
1306
1435
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 )
1308
1438
click .echo ("Added DHCP relay destination address {} to {}" .format (dhcp_relay_destination_ip , vlan_name ))
1309
1439
try :
1310
1440
click .echo ("Restarting DHCP relay service..." )
@@ -1329,7 +1459,11 @@ def del_vlan_dhcp_relay_destination(ctx, vid, dhcp_relay_destination_ip):
1329
1459
dhcp_relay_dests = vlan .get ('dhcp_servers' , [])
1330
1460
if dhcp_relay_destination_ip in dhcp_relay_dests :
1331
1461
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 )
1333
1467
click .echo ("Removed DHCP relay destination address {} from {}" .format (dhcp_relay_destination_ip , vlan_name ))
1334
1468
try :
1335
1469
click .echo ("Restarting DHCP relay service..." )
@@ -2253,6 +2387,48 @@ def platform():
2253
2387
if asic_type == 'mellanox' :
2254
2388
platform .add_command (mlnx .mlnx )
2255
2389
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
+
2256
2432
#
2257
2433
# 'watermark' group ("show watermark telemetry interval")
2258
2434
#
@@ -2732,5 +2908,41 @@ def feature_status(name, state):
2732
2908
2733
2909
config_db .mod_entry ('FEATURE' , name , {'status' : state })
2734
2910
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
+
2735
2947
if __name__ == '__main__' :
2736
2948
config ()
0 commit comments