@@ -29,11 +29,15 @@ import (
2929 "syscall"
3030 "strings"
3131 "flag"
32+ "github.com/go-redis/redis"
3233 log "github.com/golang/glog"
3334)
3435
3536var CVL_SCHEMA string = "/usr/sbin/schema/"
3637var CVL_CFG_FILE string = "/usr/sbin/cvl_cfg.json"
38+ const SONIC_DB_CONFIG_FILE string = "/var/run/redis/sonic-db/database_config.json"
39+ const ENV_VAR_SONIC_DB_CONFIG_FILE = "DB_CONFIG_PATH"
40+ var sonic_db_config = make (map [string ]interface {})
3741
3842//package init function
3943func init () {
@@ -44,6 +48,9 @@ func init() {
4448 if (os .Getenv ("CVL_CFG_FILE" ) != "" ) {
4549 CVL_CFG_FILE = os .Getenv ("CVL_CFG_FILE" )
4650 }
51+
52+ //Initialize DB settings
53+ dbCfgInit ()
4754}
4855
4956var cvlCfgMap map [string ]string
@@ -253,3 +260,184 @@ func SkipSemanticValidation() bool {
253260
254261 return false
255262}
263+
264+ //Function to read Redis DB configuration from file.
265+ //In absence of the file, it uses default config for CONFIG_DB
266+ //so that CVL UT will pass in development environment.
267+ func dbCfgInit () {
268+ defaultDBConfig := `{
269+ "INSTANCES": {
270+ "redis":{
271+ "hostname" : "127.0.0.1",
272+ "port" : 6379
273+ }
274+ },
275+ "DATABASES" : {
276+ "CONFIG_DB" : {
277+ "id" : 4,
278+ "separator": "|",
279+ "instance" : "redis"
280+ },
281+ "STATE_DB" : {
282+ "id" : 6,
283+ "separator": "|",
284+ "instance" : "redis"
285+ }
286+ }
287+ }`
288+
289+ dbCfgFile := ""
290+
291+ //Check if multi-db config file is present
292+ if _ , errF := os .Stat (SONIC_DB_CONFIG_FILE ); ! os .IsNotExist (errF ) {
293+ dbCfgFile = SONIC_DB_CONFIG_FILE
294+ } else {
295+ //Check if multi-db config file is specified in environment
296+ if fileName := os .Getenv (ENV_VAR_SONIC_DB_CONFIG_FILE ); fileName != "" {
297+ if _ , errF := os .Stat (fileName ); ! os .IsNotExist (errF ) {
298+ dbCfgFile = fileName
299+ }
300+ }
301+ }
302+
303+ if dbCfgFile != "" {
304+ //Read from multi-db config file
305+ data , err := ioutil .ReadFile (dbCfgFile )
306+ if err != nil {
307+ panic (err )
308+ } else {
309+ err = json .Unmarshal ([]byte (data ), & sonic_db_config )
310+ if err != nil {
311+ panic (err )
312+ }
313+ }
314+ } else {
315+ //No multi-db config file is present.
316+ //Use default config for CONFIG_DB setting, this avoids CVL UT failure
317+ //in absence of at multi-db config file
318+ err := json .Unmarshal ([]byte (defaultDBConfig ), & sonic_db_config )
319+ if err != nil {
320+ panic (err )
321+ }
322+ }
323+ }
324+
325+ //Get list of DB
326+ func getDbList ()(map [string ]interface {}) {
327+ db_list , ok := sonic_db_config ["DATABASES" ].(map [string ]interface {})
328+ if ! ok {
329+ panic (fmt .Errorf ("DATABASES' is not valid key in %s!" ,
330+ SONIC_DB_CONFIG_FILE ))
331+ }
332+ return db_list
333+ }
334+
335+ //Get DB instance based on given DB name
336+ func getDbInst (dbName string )(map [string ]interface {}) {
337+ db , ok := sonic_db_config ["DATABASES" ].(map [string ]interface {})[dbName ]
338+ if ! ok {
339+ panic (fmt .Errorf ("database name '%v' is not valid in %s !" ,
340+ dbName , SONIC_DB_CONFIG_FILE ))
341+ }
342+ inst_name , ok := db .(map [string ]interface {})["instance" ]
343+ if ! ok {
344+ panic (fmt .Errorf ("'instance' is not a valid field in %s !" ,
345+ SONIC_DB_CONFIG_FILE ))
346+ }
347+ inst , ok := sonic_db_config ["INSTANCES" ].(map [string ]interface {})[inst_name .(string )]
348+ if ! ok {
349+ panic (fmt .Errorf ("instance name '%v' is not valid in %s !" ,
350+ inst_name , SONIC_DB_CONFIG_FILE ))
351+ }
352+ return inst .(map [string ]interface {})
353+ }
354+
355+ //GetDbSeparator Get DB separator based on given DB name
356+ func GetDbSeparator (dbName string )(string ) {
357+ db_list := getDbList ()
358+ separator , ok := db_list [dbName ].(map [string ]interface {})["separator" ]
359+ if ! ok {
360+ panic (fmt .Errorf ("'separator' is not a valid field in %s !" ,
361+ SONIC_DB_CONFIG_FILE ))
362+ }
363+ return separator .(string )
364+ }
365+
366+ //GetDbId Get DB id on given db name
367+ func GetDbId (dbName string )(int ) {
368+ db_list := getDbList ()
369+ id , ok := db_list [dbName ].(map [string ]interface {})["id" ]
370+ if ! ok {
371+ panic (fmt .Errorf ("'id' is not a valid field in %s !" ,
372+ SONIC_DB_CONFIG_FILE ))
373+ }
374+ return int (id .(float64 ))
375+ }
376+
377+ //GetDbSock Get DB socket path
378+ func GetDbSock (dbName string )(string ) {
379+ inst := getDbInst (dbName )
380+ unix_socket_path , ok := inst ["unix_socket_path" ]
381+ if ! ok {
382+ CVL_LEVEL_LOG (INFO , "'unix_socket_path' is not " +
383+ "a valid field in %s !" , SONIC_DB_CONFIG_FILE )
384+
385+ return ""
386+ }
387+
388+ return unix_socket_path .(string )
389+ }
390+
391+ //GetDbTcpAddr Get DB TCP endpoint
392+ func GetDbTcpAddr (dbName string )(string ) {
393+ inst := getDbInst (dbName )
394+ hostname , ok := inst ["hostname" ]
395+ if ! ok {
396+ panic (fmt .Errorf ("'hostname' is not a valid field in %s !" ,
397+ SONIC_DB_CONFIG_FILE ))
398+ }
399+
400+ port , ok1 := inst ["port" ]
401+ if ! ok1 {
402+ panic (fmt .Errorf ("'port' is not a valid field in %s !" ,
403+ SONIC_DB_CONFIG_FILE ))
404+ }
405+
406+ return fmt .Sprintf ("%v:%v" , hostname , port )
407+ }
408+
409+ //NewDbClient Get new redis client
410+ func NewDbClient (dbName string ) * redis.Client {
411+ var redisClient * redis.Client = nil
412+
413+ //Try unix domain socket first
414+ if dbSock := GetDbSock (dbName ); dbSock != "" {
415+ redisClient = redis .NewClient (& redis.Options {
416+ Network : "unix" ,
417+ Addr : dbSock ,
418+ Password : "" ,
419+ DB : GetDbId (dbName ),
420+ })
421+ } else {
422+ //Otherwise, use TCP socket
423+ redisClient = redis .NewClient (& redis.Options {
424+ Network : "tcp" ,
425+ Addr : GetDbTcpAddr (dbName ),
426+ Password : "" ,
427+ DB : GetDbId (dbName ),
428+ })
429+ }
430+
431+ if (redisClient == nil ) {
432+ return nil
433+ }
434+
435+ //Check the connectivity
436+ _ , err := redisClient .Ping ().Result ()
437+ if err != nil {
438+ CVL_LEVEL_LOG (ERROR , "Failed to connect to Redis server %v" , err )
439+ return nil
440+ }
441+
442+ return redisClient
443+ }
0 commit comments