Skip to content
This repository was archived by the owner on Mar 1, 2023. It is now read-only.

Commit 904ce18

Browse files
authored
CVL Changes #3: Multi-db instance support (#20)
Adding multi-db instance support based on db config file. So, now instead of hardcoded DB endpoint, it is read from a configuration file.
1 parent 9d24a34 commit 904ce18

File tree

3 files changed

+200
-21
lines changed

3 files changed

+200
-21
lines changed

cvl/cvl_api.go

+7-11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ package cvl
2222
import (
2323
"fmt"
2424
"encoding/json"
25-
"github.com/go-redis/redis"
2625
"path/filepath"
2726
"github.com/Azure/sonic-mgmt-common/cvl/internal/yparser"
2827
. "github.com/Azure/sonic-mgmt-common/cvl/internal/util"
@@ -135,6 +134,13 @@ func Initialize() CVLRetCode {
135134
return CVL_SUCCESS
136135
}
137136

137+
//Initialize redis Client
138+
redisClient = NewDbClient("CONFIG_DB")
139+
140+
if (redisClient == nil) {
141+
CVL_LOG(FATAL, "Unable to connect to Redis Config DB Server")
142+
return CVL_ERROR
143+
}
138144
//Scan schema directory to get all schema files
139145
modelFiles, err := filepath.Glob(CVL_SCHEMA + "/*.yin")
140146
if err != nil {
@@ -169,16 +175,6 @@ func Initialize() CVLRetCode {
169175

170176
//Initialize redis Client
171177

172-
redisClient = redis.NewClient(&redis.Options{
173-
Addr: ":6379",
174-
Password: "", // no password set
175-
DB: int(CONFIG_DB), // use APP DB
176-
})
177-
178-
if (redisClient == nil) {
179-
CVL_LOG(FATAL, "Unable to connect with Redis Config DB")
180-
return CVL_ERROR
181-
}
182178

183179
//Load lua script into redis
184180
loadLuaScript()

cvl/cvl_test.go

+5-10
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,12 @@ func compareErrorDetails(cvlErr cvl.CVLErrorInfo, expCode cvl.CVLRetCode, errApp
196196
}
197197

198198
func getConfigDbClient() *redis.Client {
199-
rclient := redis.NewClient(&redis.Options{
200-
Network: "tcp",
201-
Addr: "localhost:6379",
202-
Password: "", // no password set
203-
DB: 4,
204-
DialTimeout: 0,
205-
})
206-
_, err := rclient.Ping().Result()
207-
if err != nil {
208-
fmt.Printf("failed to connect to redis server %v", err)
199+
rclient := NewDbClient("CONFIG_DB")
200+
201+
if rclient == nil {
202+
panic("Unable to connect to Redis Config DB Server")
209203
}
204+
210205
return rclient
211206
}
212207

cvl/internal/util/util.go

+188
Original file line numberDiff line numberDiff line change
@@ -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

3536
var CVL_SCHEMA string = "/usr/sbin/schema/"
3637
var 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
3943
func 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

4956
var 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

Comments
 (0)