Skip to content

Commit 1425d56

Browse files
authored
Update incremental config to support multi-asic (#355)
Fix sonic-net/sonic-buildimage#20875 Why I did it GNMI set does not support multi-asic environment How I did it Add namespace in GCU patch for multi-asic How to verify it Run gnmi unit test and end to end test
1 parent 22f767f commit 1425d56

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

gnmi_server/server_test.go

+50-1
Original file line numberDiff line numberDiff line change
@@ -4381,7 +4381,7 @@ func TestGNMINative(t *testing.T) {
43814381

43824382
// This test is used for single database configuration
43834383
// Run tests not marked with multidb
4384-
cmd := exec.Command("bash", "-c", "cd "+path+" && "+"pytest -m 'not multidb'")
4384+
cmd := exec.Command("bash", "-c", "cd "+path+" && "+"pytest -m 'not multidb and not multins'")
43854385
if result, err := cmd.Output(); err != nil {
43864386
fmt.Println(string(result))
43874387
t.Errorf("Fail to execute pytest: %v", err)
@@ -4441,6 +4441,55 @@ func TestGNMINativeMultiDB(t *testing.T) {
44414441
}
44424442
}
44434443

4444+
// Test configuration with multiple namespaces
4445+
func TestGNMINativeMultiNamespace(t *testing.T) {
4446+
mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) {
4447+
return &dbus.Conn{}, nil
4448+
})
4449+
defer mock1.Reset()
4450+
mock2 := gomonkey.ApplyMethod(reflect.TypeOf(&dbus.Object{}), "Go", func(obj *dbus.Object, method string, flags dbus.Flags, ch chan *dbus.Call, args ...interface{}) *dbus.Call {
4451+
ret := &dbus.Call{}
4452+
ret.Err = nil
4453+
ret.Body = make([]interface{}, 2)
4454+
ret.Body[0] = int32(0)
4455+
ch <- ret
4456+
return &dbus.Call{}
4457+
})
4458+
defer mock2.Reset()
4459+
sdcfg.Init()
4460+
err := test_utils.SetupMultiNamespace()
4461+
if err != nil {
4462+
t.Fatalf("error Setting up MultiNamespace files with err %T", err)
4463+
}
4464+
4465+
/* https://www.gopherguides.com/articles/test-cleanup-in-go-1-14*/
4466+
t.Cleanup(func() {
4467+
if err := test_utils.CleanUpMultiNamespace(); err != nil {
4468+
t.Fatalf("error Cleaning up MultiNamespace files with err %T", err)
4469+
4470+
}
4471+
})
4472+
4473+
s := createServer(t, 8080)
4474+
go runServer(t, s)
4475+
defer s.Stop()
4476+
ns, _ := sdcfg.GetDbDefaultNamespace()
4477+
initFullConfigDb(t, ns)
4478+
4479+
path, _ := os.Getwd()
4480+
path = filepath.Dir(path)
4481+
4482+
// This test is used for multiple namespaces configuration
4483+
// Run tests marked with multins
4484+
cmd := exec.Command("bash", "-c", "cd "+path+" && "+"pytest -m 'multins'")
4485+
if result, err := cmd.Output(); err != nil {
4486+
fmt.Println(string(result))
4487+
t.Errorf("Fail to execute pytest: %v", err)
4488+
} else {
4489+
fmt.Println(string(result))
4490+
}
4491+
}
4492+
44444493
func TestServerPort(t *testing.T) {
44454494
s := createServer(t, -8080)
44464495
port := s.Port()

pytest.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[pytest]
22
markers:
33
multidb
4+
multins

sonic_data_client/mixed_db_client.go

+23-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const ELEM_INDEX_INSTANCE = 1
4747
const UPDATE_OPERATION = "add"
4848
const DELETE_OPERATION = "remove"
4949
const REPLACE_OPERATION = "replace"
50+
const HOSTNAME = "localhost"
5051

5152
const (
5253
opAdd = iota
@@ -389,7 +390,7 @@ func (c *MixedDbClient) ParseDatabase(prefix *gnmipb.Path, paths []*gnmipb.Path)
389390
if c.namespace_cnt > 1 && c.container_cnt > 1 {
390391
// Support smartswitch with multiple asic NPU
391392
// The elelement can be "localhost", "asic0", "asic1", ..., "dpu0", "dpu1", ...
392-
if elem_name != "localhost" {
393+
if elem_name != HOSTNAME {
393394
// Try namespace
394395
dbkey1, ok := sdcfg.GetDbInstanceFromTarget(elem_name, sdcfg.SONIC_DEFAULT_CONTAINER)
395396
if ok {
@@ -419,11 +420,11 @@ func (c *MixedDbClient) ParseDatabase(prefix *gnmipb.Path, paths []*gnmipb.Path)
419420
return "", nil, status.Error(codes.Unimplemented, "No target specified in path")
420421
}
421422
// GNMI path uses localhost as default namespace
422-
if namespace == "localhost" {
423+
if namespace == HOSTNAME {
423424
namespace = sdcfg.SONIC_DEFAULT_NAMESPACE
424425
}
425426
// GNMI path uses localhost as default container
426-
if container == "localhost" {
427+
if container == HOSTNAME {
427428
container = sdcfg.SONIC_DEFAULT_NAMESPACE
428429
}
429430
dbkey := swsscommon.NewSonicDBKey()
@@ -1227,6 +1228,16 @@ func (c *MixedDbClient) SetIncrementalConfig(delete []*gnmipb.Path, replace []*g
12271228
return err
12281229
}
12291230

1231+
multiNs, err := sdcfg.CheckDbMultiNamespace()
1232+
if err != nil {
1233+
return err
1234+
}
1235+
namespace := c.dbkey.GetNetns()
1236+
// Default name space for GCU is localhost
1237+
if namespace == sdcfg.SONIC_DEFAULT_NAMESPACE {
1238+
namespace = HOSTNAME
1239+
}
1240+
12301241
var patchList [](map[string]interface{})
12311242
/* DELETE */
12321243
for _, path := range delete {
@@ -1255,6 +1266,9 @@ func (c *MixedDbClient) SetIncrementalConfig(delete []*gnmipb.Path, replace []*g
12551266
if err != nil {
12561267
return err
12571268
}
1269+
if multiNs {
1270+
curr["path"] = "/" + namespace + curr["path"].(string)
1271+
}
12581272
patchList = append(patchList, curr)
12591273
}
12601274

@@ -1294,6 +1308,9 @@ func (c *MixedDbClient) SetIncrementalConfig(delete []*gnmipb.Path, replace []*g
12941308
if err != nil {
12951309
return err
12961310
}
1311+
if multiNs {
1312+
curr["path"] = "/" + namespace + curr["path"].(string)
1313+
}
12971314
patchList = append(patchList, curr)
12981315
}
12991316

@@ -1329,6 +1346,9 @@ func (c *MixedDbClient) SetIncrementalConfig(delete []*gnmipb.Path, replace []*g
13291346
if err != nil {
13301347
return err
13311348
}
1349+
if multiNs {
1350+
curr["path"] = "/" + namespace + curr["path"].(string)
1351+
}
13321352
patchList = append(patchList, curr)
13331353
}
13341354
if len(patchList) == 0 {

test/test_gnmi_configdb_patch.py

+50
Original file line numberDiff line numberDiff line change
@@ -3122,13 +3122,63 @@ def common_test_handler(self, test_data):
31223122
diff = jsonpatch.make_patch(result, test_data["target_json"])
31233123
assert len(diff.patch) == 0, "%s failed, generated json: %s" % (test_data["test_name"], str(result))
31243124

3125+
def multins_test_handler(self, test_data):
3126+
'''
3127+
Common code for multins test
3128+
'''
3129+
if os.path.exists(patch_file):
3130+
os.system("rm " + patch_file)
3131+
create_checkpoint(checkpoint_file, json.dumps(test_data['origin_json']))
3132+
update_list = []
3133+
replace_list = []
3134+
delete_list = []
3135+
for i, data in enumerate(test_data["operations"]):
3136+
path = data["path"]
3137+
if data['op'] == "update":
3138+
value = json.dumps(data["value"])
3139+
file_name = "update" + str(i)
3140+
file_object = open(file_name, "w")
3141+
file_object.write(value)
3142+
file_object.close()
3143+
update_list.append(path + ":@./" + file_name)
3144+
elif data['op'] == "replace":
3145+
value = json.dumps(data["value"])
3146+
file_name = "replace" + str(i)
3147+
file_object = open(file_name, "w")
3148+
file_object.write(value)
3149+
file_object.close()
3150+
replace_list.append(path + ":@./" + file_name)
3151+
elif data['op'] == "del":
3152+
delete_list.append(path)
3153+
else:
3154+
pytest.fail("Invalid operation: %s" % data['op'])
3155+
3156+
# Send GNMI request
3157+
ret, msg = gnmi_set(delete_list, update_list, replace_list)
3158+
assert ret == 0, msg
3159+
assert os.path.exists(patch_file), "No patch file"
3160+
with open(patch_file,"r") as pf:
3161+
patch_json = json.load(pf)
3162+
for patch in patch_json:
3163+
if "path" in patch:
3164+
path = patch["path"]
3165+
assert path.startswith("/localhost"), "Invalid path: %s" % path
3166+
31253167
@pytest.mark.parametrize("test_data", test_data_aaa_patch)
31263168
def test_gnmi_aaa_patch(self, test_data):
31273169
'''
31283170
Generate GNMI request for AAA and verify jsonpatch
31293171
'''
31303172
self.common_test_handler(test_data)
31313173

3174+
@pytest.mark.multins
3175+
@pytest.mark.parametrize("test_data", test_data_aaa_patch)
3176+
def test_gnmi_aaa_patch(self, test_data):
3177+
'''
3178+
Generate GNMI request for AAA and verify jsonpatch
3179+
'''
3180+
self.multins_test_handler(test_data)
3181+
31323182
@pytest.mark.parametrize("test_data", test_data_bgp_prefix_patch)
31333183
def test_gnmi_bgp_prefix_patch(self, test_data):
31343184
'''

0 commit comments

Comments
 (0)