31
31
from sonic_yang_cfg_generator import SonicYangCfgDbGenerator
32
32
from utilities_common import util_base
33
33
from swsscommon import swsscommon
34
- from swsscommon .swsscommon import SonicV2Connector , ConfigDBConnector
34
+ from swsscommon .swsscommon import SonicV2Connector , ConfigDBConnector , ConfigDBPipeConnector
35
35
from utilities_common .db import Db
36
36
from utilities_common .intf_filter import parse_interface_in_filter
37
37
from utilities_common import bgp_util
@@ -1197,7 +1197,7 @@ def validate_gre_type(ctx, _, value):
1197
1197
raise click .UsageError ("{} is not a valid GRE type" .format (value ))
1198
1198
1199
1199
1200
- def multi_asic_save_config (db , filename ):
1200
+ def multiasic_save_to_singlefile (db , filename ):
1201
1201
"""A function to save all asic's config to single file
1202
1202
"""
1203
1203
all_current_config = {}
@@ -1264,6 +1264,96 @@ def validate_patch(patch):
1264
1264
except Exception as e :
1265
1265
raise GenericConfigUpdaterError (f"Validate json patch: { patch } failed due to:{ e } " )
1266
1266
1267
+
1268
+ def multiasic_validate_single_file (filename ):
1269
+ ns_list = [DEFAULT_NAMESPACE , * multi_asic .get_namespace_list ()]
1270
+ file_input = read_json_file (filename )
1271
+ file_ns_list = [DEFAULT_NAMESPACE if key == HOST_NAMESPACE else key for key in file_input ]
1272
+ if set (ns_list ) != set (file_ns_list ):
1273
+ click .echo (
1274
+ "Input file {} must contain all asics config. ns_list: {} file ns_list: {}" .format (
1275
+ filename , ns_list , file_ns_list )
1276
+ )
1277
+ raise click .Abort ()
1278
+
1279
+
1280
+ def load_sysinfo_if_missing (asic_config ):
1281
+ device_metadata = asic_config .get ('DEVICE_METADATA' , {})
1282
+ platform = device_metadata .get ("localhost" , {}).get ("platform" )
1283
+ mac = device_metadata .get ("localhost" , {}).get ("mac" )
1284
+ if not platform :
1285
+ log .log_warning ("platform is missing from Input file" )
1286
+ return True
1287
+ elif not mac :
1288
+ log .log_warning ("mac is missing from Input file" )
1289
+ return True
1290
+ else :
1291
+ return False
1292
+
1293
+
1294
+ def flush_configdb (namespace = DEFAULT_NAMESPACE ):
1295
+ if namespace is DEFAULT_NAMESPACE :
1296
+ config_db = ConfigDBConnector ()
1297
+ else :
1298
+ config_db = ConfigDBConnector (use_unix_socket_path = True , namespace = namespace )
1299
+
1300
+ config_db .connect ()
1301
+ client = config_db .get_redis_client (config_db .CONFIG_DB )
1302
+ client .flushdb ()
1303
+ return client , config_db
1304
+
1305
+
1306
+ def migrate_db_to_lastest (namespace = DEFAULT_NAMESPACE ):
1307
+ # Migrate DB contents to latest version
1308
+ db_migrator = '/usr/local/bin/db_migrator.py'
1309
+ if os .path .isfile (db_migrator ) and os .access (db_migrator , os .X_OK ):
1310
+ if namespace is DEFAULT_NAMESPACE :
1311
+ command = [db_migrator , '-o' , 'migrate' ]
1312
+ else :
1313
+ command = [db_migrator , '-o' , 'migrate' , '-n' , namespace ]
1314
+ clicommon .run_command (command , display_cmd = True )
1315
+
1316
+
1317
+ def multiasic_write_to_db (filename , load_sysinfo ):
1318
+ file_input = read_json_file (filename )
1319
+ for ns in [DEFAULT_NAMESPACE , * multi_asic .get_namespace_list ()]:
1320
+ asic_name = HOST_NAMESPACE if ns == DEFAULT_NAMESPACE else ns
1321
+ asic_config = file_input [asic_name ]
1322
+
1323
+ asic_load_sysinfo = True if load_sysinfo else False
1324
+ if not asic_load_sysinfo :
1325
+ asic_load_sysinfo = load_sysinfo_if_missing (asic_config )
1326
+
1327
+ if asic_load_sysinfo :
1328
+ cfg_hwsku = asic_config .get ("DEVICE_METADATA" , {}).\
1329
+ get ("localhost" , {}).get ("hwsku" )
1330
+ if not cfg_hwsku :
1331
+ click .secho ("Could not get the HWSKU from config file, Exiting!" , fg = 'magenta' )
1332
+ sys .exit (1 )
1333
+
1334
+ client , _ = flush_configdb (ns )
1335
+
1336
+ if asic_load_sysinfo :
1337
+ if ns is DEFAULT_NAMESPACE :
1338
+ command = [str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '--write-to-db' ]
1339
+ else :
1340
+ command = [str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '-n' , str (ns ), '--write-to-db' ]
1341
+ clicommon .run_command (command , display_cmd = True )
1342
+
1343
+ if ns is DEFAULT_NAMESPACE :
1344
+ config_db = ConfigDBPipeConnector (use_unix_socket_path = True )
1345
+ else :
1346
+ config_db = ConfigDBPipeConnector (use_unix_socket_path = True , namespace = ns )
1347
+
1348
+ config_db .connect (False )
1349
+ sonic_cfggen .FormatConverter .to_deserialized (asic_config )
1350
+ data = sonic_cfggen .FormatConverter .output_to_db (asic_config )
1351
+ config_db .mod_config (sonic_cfggen .FormatConverter .output_to_db (data ))
1352
+ client .set (config_db .INIT_INDICATOR , 1 )
1353
+
1354
+ migrate_db_to_lastest (ns )
1355
+
1356
+
1267
1357
# This is our main entrypoint - the main 'config' command
1268
1358
@click .group (cls = clicommon .AbbreviationGroup , context_settings = CONTEXT_SETTINGS )
1269
1359
@click .pass_context
@@ -1351,7 +1441,7 @@ def save(db, filename):
1351
1441
# save all ASIC configurations to that single file.
1352
1442
if len (cfg_files ) == 1 and multi_asic .is_multi_asic ():
1353
1443
filename = cfg_files [0 ]
1354
- multi_asic_save_config (db , filename )
1444
+ multiasic_save_to_singlefile (db , filename )
1355
1445
return
1356
1446
elif len (cfg_files ) != num_cfg_file :
1357
1447
click .echo ("Input {} config file(s) separated by comma for multiple files " .format (num_cfg_file ))
@@ -1669,11 +1759,15 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, force, file_form
1669
1759
if multi_asic .is_multi_asic () and file_format == 'config_db' :
1670
1760
num_cfg_file += num_asic
1671
1761
1762
+ multiasic_single_file_mode = False
1672
1763
# If the user give the filename[s], extract the file names.
1673
1764
if filename is not None :
1674
1765
cfg_files = filename .split (',' )
1675
1766
1676
- if len (cfg_files ) != num_cfg_file :
1767
+ if len (cfg_files ) == 1 and multi_asic .is_multi_asic ():
1768
+ multiasic_validate_single_file (cfg_files [0 ])
1769
+ multiasic_single_file_mode = True
1770
+ elif len (cfg_files ) != num_cfg_file :
1677
1771
click .echo ("Input {} config file(s) separated by comma for multiple files " .format (num_cfg_file ))
1678
1772
return
1679
1773
@@ -1682,127 +1776,109 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, force, file_form
1682
1776
log .log_notice ("'reload' stopping services..." )
1683
1777
_stop_services ()
1684
1778
1685
- # In Single ASIC platforms we have single DB service. In multi-ASIC platforms we have a global DB
1686
- # service running in the host + DB services running in each ASIC namespace created per ASIC.
1687
- # In the below logic, we get all namespaces in this platform and add an empty namespace ''
1688
- # denoting the current namespace which we are in ( the linux host )
1689
- for inst in range (- 1 , num_cfg_file - 1 ):
1690
- # Get the namespace name, for linux host it is None
1691
- if inst == - 1 :
1692
- namespace = None
1693
- else :
1694
- namespace = "{}{}" .format (NAMESPACE_PREFIX , inst )
1695
-
1696
- # Get the file from user input, else take the default file /etc/sonic/config_db{NS_id}.json
1697
- if cfg_files :
1698
- file = cfg_files [inst + 1 ]
1699
- # Save to tmpfile in case of stdin input which can only be read once
1700
- if file == "/dev/stdin" :
1701
- file_input = read_json_file (file )
1702
- (_ , tmpfname ) = tempfile .mkstemp (dir = "/tmp" , suffix = "_configReloadStdin" )
1703
- write_json_file (file_input , tmpfname )
1704
- file = tmpfname
1705
- else :
1706
- if file_format == 'config_db' :
1707
- if namespace is None :
1708
- file = DEFAULT_CONFIG_DB_FILE
1709
- else :
1710
- file = "/etc/sonic/config_db{}.json" .format (inst )
1779
+ if multiasic_single_file_mode :
1780
+ multiasic_write_to_db (cfg_files [0 ], load_sysinfo )
1781
+ else :
1782
+ # In Single ASIC platforms we have single DB service. In multi-ASIC platforms we have a global DB
1783
+ # service running in the host + DB services running in each ASIC namespace created per ASIC.
1784
+ # In the below logic, we get all namespaces in this platform and add an empty namespace ''
1785
+ # denoting the current namespace which we are in ( the linux host )
1786
+ for inst in range (- 1 , num_cfg_file - 1 ):
1787
+ # Get the namespace name, for linux host it is DEFAULT_NAMESPACE
1788
+ if inst == - 1 :
1789
+ namespace = DEFAULT_NAMESPACE
1711
1790
else :
1712
- file = DEFAULT_CONFIG_YANG_FILE
1713
-
1714
-
1715
- # Check the file exists before proceeding.
1716
- if not os .path .exists (file ):
1717
- click .echo ("The config file {} doesn't exist" .format (file ))
1718
- continue
1719
-
1720
- if file_format == 'config_db' :
1721
- file_input = read_json_file (file )
1791
+ namespace = "{}{}" .format (NAMESPACE_PREFIX , inst )
1792
+
1793
+ # Get the file from user input, else take the default file /etc/sonic/config_db{NS_id}.json
1794
+ if cfg_files :
1795
+ file = cfg_files [inst + 1 ]
1796
+ # Save to tmpfile in case of stdin input which can only be read once
1797
+ if file == "/dev/stdin" :
1798
+ file_input = read_json_file (file )
1799
+ (_ , tmpfname ) = tempfile .mkstemp (dir = "/tmp" , suffix = "_configReloadStdin" )
1800
+ write_json_file (file_input , tmpfname )
1801
+ file = tmpfname
1802
+ else :
1803
+ if file_format == 'config_db' :
1804
+ if namespace is DEFAULT_NAMESPACE :
1805
+ file = DEFAULT_CONFIG_DB_FILE
1806
+ else :
1807
+ file = "/etc/sonic/config_db{}.json" .format (inst )
1808
+ else :
1809
+ file = DEFAULT_CONFIG_YANG_FILE
1722
1810
1723
- platform = file_input . get ( "DEVICE_METADATA" , {}).\
1724
- get ( HOST_NAMESPACE , {}). get ( "platform" )
1725
- mac = file_input . get ( "DEVICE_METADATA" , {}).\
1726
- get ( HOST_NAMESPACE , {}). get ( "mac" )
1811
+ # Check the file exists before proceeding.
1812
+ if not os . path . exists ( file ):
1813
+ click . echo ( "The config file {} doesn't exist" . format ( file ))
1814
+ continue
1727
1815
1728
- if not platform or not mac :
1729
- log .log_warning ("Input file does't have platform or mac. platform: {}, mac: {}"
1730
- .format (None if platform is None else platform , None if mac is None else mac ))
1731
- load_sysinfo = True
1816
+ if file_format == 'config_db' :
1817
+ file_input = read_json_file (file )
1818
+ if not load_sysinfo :
1819
+ load_sysinfo = load_sysinfo_if_missing (file_input )
1820
+
1821
+ if load_sysinfo :
1822
+ try :
1823
+ command = [SONIC_CFGGEN_PATH , "-j" , file , '-v' , "DEVICE_METADATA.localhost.hwsku" ]
1824
+ proc = subprocess .Popen (command , text = True , stdout = subprocess .PIPE )
1825
+ output , err = proc .communicate ()
1826
+
1827
+ except FileNotFoundError as e :
1828
+ click .echo ("{}" .format (str (e )), err = True )
1829
+ raise click .Abort ()
1830
+ except Exception as e :
1831
+ click .echo ("{}\n {}" .format (type (e ), str (e )), err = True )
1832
+ raise click .Abort ()
1833
+
1834
+ if not output :
1835
+ click .secho ("Could not get the HWSKU from config file, Exiting!!!" , fg = 'magenta' )
1836
+ sys .exit (1 )
1732
1837
1733
- if load_sysinfo :
1734
- try :
1735
- command = [SONIC_CFGGEN_PATH , "-j" , file , '-v' , "DEVICE_METADATA.localhost.hwsku" ]
1736
- proc = subprocess .Popen (command , text = True , stdout = subprocess .PIPE )
1737
- output , err = proc .communicate ()
1838
+ cfg_hwsku = output .strip ()
1738
1839
1739
- except FileNotFoundError as e :
1740
- click .echo ("{}" .format (str (e )), err = True )
1741
- raise click .Abort ()
1742
- except Exception as e :
1743
- click .echo ("{}\n {}" .format (type (e ), str (e )), err = True )
1744
- raise click .Abort ()
1840
+ client , config_db = flush_configdb (namespace )
1745
1841
1746
- if not output :
1747
- click .secho ("Could not get the HWSKU from config file, Exiting!!!" , fg = 'magenta' )
1748
- sys .exit (1 )
1842
+ if load_sysinfo :
1843
+ if namespace is DEFAULT_NAMESPACE :
1844
+ command = [
1845
+ str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '--write-to-db' ]
1846
+ else :
1847
+ command = [
1848
+ str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '-n' , str (namespace ), '--write-to-db' ]
1849
+ clicommon .run_command (command , display_cmd = True )
1749
1850
1750
- cfg_hwsku = output .strip ()
1851
+ # For the database service running in linux host we use the file user gives as input
1852
+ # or by default DEFAULT_CONFIG_DB_FILE. In the case of database service running in namespace,
1853
+ # the default config_db<namespaceID>.json format is used.
1751
1854
1752
- if namespace is None :
1753
- config_db = ConfigDBConnector ()
1754
- else :
1755
- config_db = ConfigDBConnector (use_unix_socket_path = True , namespace = namespace )
1855
+ config_gen_opts = []
1756
1856
1757
- config_db .connect ()
1758
- client = config_db .get_redis_client (config_db .CONFIG_DB )
1759
- client .flushdb ()
1857
+ if os .path .isfile (INIT_CFG_FILE ):
1858
+ config_gen_opts += ['-j' , str (INIT_CFG_FILE )]
1760
1859
1761
- if load_sysinfo :
1762
- if namespace is None :
1763
- command = [str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '--write-to-db' ]
1860
+ if file_format == 'config_db' :
1861
+ config_gen_opts += ['-j' , str (file )]
1764
1862
else :
1765
- command = [str (SONIC_CFGGEN_PATH ), '-H' , '-k' , str (cfg_hwsku ), '-n' , str (namespace ), '--write-to-db' ]
1766
- clicommon .run_command (command , display_cmd = True )
1767
-
1768
- # For the database service running in linux host we use the file user gives as input
1769
- # or by default DEFAULT_CONFIG_DB_FILE. In the case of database service running in namespace,
1770
- # the default config_db<namespaceID>.json format is used.
1771
-
1863
+ config_gen_opts += ['-Y' , str (file )]
1772
1864
1773
- config_gen_opts = []
1865
+ if namespace is not DEFAULT_NAMESPACE :
1866
+ config_gen_opts += ['-n' , str (namespace )]
1774
1867
1775
- if os .path .isfile (INIT_CFG_FILE ):
1776
- config_gen_opts += ['-j' , str (INIT_CFG_FILE )]
1868
+ command = [SONIC_CFGGEN_PATH ] + config_gen_opts + ['--write-to-db' ]
1777
1869
1778
- if file_format == 'config_db' :
1779
- config_gen_opts += ['-j' , str (file )]
1780
- else :
1781
- config_gen_opts += ['-Y' , str (file )]
1782
-
1783
- if namespace is not None :
1784
- config_gen_opts += ['-n' , str (namespace )]
1785
-
1786
- command = [SONIC_CFGGEN_PATH ] + config_gen_opts + ['--write-to-db' ]
1787
-
1788
- clicommon .run_command (command , display_cmd = True )
1789
- client .set (config_db .INIT_INDICATOR , 1 )
1870
+ clicommon .run_command (command , display_cmd = True )
1871
+ client .set (config_db .INIT_INDICATOR , 1 )
1790
1872
1791
- if os .path .exists (file ) and file .endswith ("_configReloadStdin" ):
1792
- # Remove tmpfile
1793
- try :
1794
- os .remove (file )
1795
- except OSError as e :
1796
- click .echo ("An error occurred while removing the temporary file: {}" .format (str (e )), err = True )
1873
+ if os .path .exists (file ) and file .endswith ("_configReloadStdin" ):
1874
+ # Remove tmpfile
1875
+ try :
1876
+ os .remove (file )
1877
+ except OSError as e :
1878
+ click .echo ("An error occurred while removing the temporary file: {}" .format (str (e )), err = True )
1797
1879
1798
- # Migrate DB contents to latest version
1799
- db_migrator = '/usr/local/bin/db_migrator.py'
1800
- if os .path .isfile (db_migrator ) and os .access (db_migrator , os .X_OK ):
1801
- if namespace is None :
1802
- command = [db_migrator , '-o' , 'migrate' ]
1803
- else :
1804
- command = [db_migrator , '-o' , 'migrate' , '-n' , str (namespace )]
1805
- clicommon .run_command (command , display_cmd = True )
1880
+ # Migrate DB contents to latest version
1881
+ migrate_db_to_lastest (namespace )
1806
1882
1807
1883
# Re-generate the environment variable in case config_db.json was edited
1808
1884
update_sonic_environment ()
@@ -4086,6 +4162,7 @@ def bgp():
4086
4162
pass
4087
4163
4088
4164
4165
+
4089
4166
# BGP module extensions
4090
4167
config .commands ['bgp' ].add_command (bgp_cli .DEVICE_GLOBAL )
4091
4168
0 commit comments