From 2c8e4ab783d10b7433325653c1c90ad2b7f980b0 Mon Sep 17 00:00:00 2001 From: ganglv <88995770+ganglyu@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:58:24 +0800 Subject: [PATCH] Support proto encoding (#140) Why I did it Need to support GNMI request with proto encoding. How I did it Update gnmi client and gnmi server to support both json ietf and proto encoding. How to verify it Run GNMI unit test. --- gnmi_server/server.go | 10 +- patches/gnmi_get.patch | 43 ++++++++- patches/gnmi_set.patch | 22 ++++- sonic_data_client/db_client.go | 3 +- sonic_data_client/mixed_db_client.go | 136 ++++++++++++++++++--------- test/test_gnmi_appldb.py | 122 +++++++++++++++++++++++- test/utils.py | 14 +++ 7 files changed, 291 insertions(+), 59 deletions(-) diff --git a/gnmi_server/server.go b/gnmi_server/server.go index 10f087d8..5661752c 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -27,7 +27,7 @@ import ( ) var ( - supportedEncodings = []gnmipb.Encoding{gnmipb.Encoding_JSON, gnmipb.Encoding_JSON_IETF} + supportedEncodings = []gnmipb.Encoding{gnmipb.Encoding_JSON, gnmipb.Encoding_JSON_IETF, gnmipb.Encoding_PROTO} ) // Server manages a single gNMI Server implementation. Each client that connects @@ -329,6 +329,7 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe paths := req.GetPath() extensions := req.GetExtension() + encoding := req.GetEncoding() log.V(2).Infof("GetRequest paths: %v", paths) var dc sdc.Client @@ -344,7 +345,7 @@ func (s *Server) Get(ctx context.Context, req *gnmipb.GetRequest) (*gnmipb.GetRe return nil, err } if check := IsNativeOrigin(origin); check { - dc, err = sdc.NewMixedDbClient(paths, prefix, origin, s.config.ZmqAddress) + dc, err = sdc.NewMixedDbClient(paths, prefix, origin, encoding, s.config.ZmqAddress) } else { dc, err = sdc.NewTranslClient(prefix, paths, ctx, extensions) } @@ -393,6 +394,7 @@ func (s *Server) Set(ctx context.Context, req *gnmipb.SetRequest) (*gnmipb.SetRe /* Fetch the prefix. */ prefix := req.GetPrefix() extensions := req.GetExtension() + encoding := gnmipb.Encoding_JSON_IETF var dc sdc.Client paths := req.GetDelete() @@ -411,7 +413,7 @@ func (s *Server) Set(ctx context.Context, req *gnmipb.SetRequest) (*gnmipb.SetRe common_utils.IncCounter(common_utils.GNMI_SET_FAIL) return nil, grpc.Errorf(codes.Unimplemented, "GNMI native write is disabled") } - dc, err = sdc.NewMixedDbClient(paths, prefix, origin, s.config.ZmqAddress) + dc, err = sdc.NewMixedDbClient(paths, prefix, origin, encoding, s.config.ZmqAddress) } else { if s.config.EnableTranslibWrite == false { common_utils.IncCounter(common_utils.GNMI_SET_FAIL) @@ -486,7 +488,7 @@ func (s *Server) Capabilities(ctx context.Context, req *gnmipb.CapabilityRequest var supportedModels []gnmipb.ModelData dc, _ := sdc.NewTranslClient(nil, nil, ctx, extensions) supportedModels = append(supportedModels, dc.Capabilities()...) - dc, _ = sdc.NewMixedDbClient(nil, nil, "", s.config.ZmqAddress) + dc, _ = sdc.NewMixedDbClient(nil, nil, "", gnmipb.Encoding_JSON_IETF, s.config.ZmqAddress) supportedModels = append(supportedModels, dc.Capabilities()...) suppModels := make([]*gnmipb.ModelData, len(supportedModels)) diff --git a/patches/gnmi_get.patch b/patches/gnmi_get.patch index 5d27653f..39a1eea9 100644 --- a/patches/gnmi_get.patch +++ b/patches/gnmi_get.patch @@ -1,6 +1,14 @@ --- ./github.com/jipanyang/gnxi/gnmi_get/gnmi_get.go 2019-11-26 15:44:07.303598063 -0800 +++ ./github.com/jipanyang/gnxi/gnmi_get/gnmi_get.go 2019-12-19 19:56:11.364223008 -0800 -@@ -30,7 +30,7 @@ +@@ -21,6 +21,7 @@ + "fmt" + "strings" + "time" ++ "io/ioutil" + + log "github.com/golang/glog" + "github.com/golang/protobuf/proto" +@@ -30,7 +31,7 @@ "github.com/google/gnxi/utils" "github.com/google/gnxi/utils/credentials" "github.com/jipanyang/gnxi/utils/xpath" @@ -9,11 +17,12 @@ pb "github.com/openconfig/gnmi/proto/gnmi" ) -@@ -63,11 +63,12 @@ +@@ -63,17 +64,20 @@ xPathFlags arrayFlags pbPathFlags arrayFlags pbModelDataFlags arrayFlags - pathTarget = flag.String("xpath_target", "CONFIG_DB", "name of the target for which the path is a member") ++ protoFileFlags arrayFlags + pathTarget = flag.String("xpath_target", "", "name of the target for which the path is a member") targetAddr = flag.String("target_addr", "localhost:10161", "The target address in the format of host:port") targetName = flag.String("target_name", "hostname.com", "The target name use to verify the hostname returned by TLS handshake") @@ -23,7 +32,14 @@ ) func main() { -@@ -88,6 +89,10 @@ + flag.Var(&xPathFlags, "xpath", "xpath of the config node to be fetched") + flag.Var(&pbPathFlags, "pbpath", "protobuf format path of the config node to be fetched") + flag.Var(&pbModelDataFlags, "model_data", "Data models to be used by the target in the format of 'name,organization,version'") ++ flag.Var(&protoFileFlags, "proto_file", "Files for proto bytes in get response") + flag.Parse() + + opts := credentials.ClientCredentials(*targetName) +@@ -88,6 +92,10 @@ ctx, cancel := context.WithTimeout(context.Background(), *timeOut) defer cancel() @@ -34,3 +50,24 @@ encoding, ok := pb.Encoding_value[*encodingName] if !ok { var gnmiEncodingList []string +@@ -139,4 +147,20 @@ + + fmt.Println("== getResponse:") + utils.PrintProto(getResponse) ++ ++ if *encodingName == "PROTO" { ++ cnt := 0 ++ for _, notification := range getResponse.GetNotification() { ++ for _, update := range notification.GetUpdate() { ++ val := update.GetVal() ++ protoBytes := val.GetProtoBytes() ++ fileName := protoFileFlags[cnt] ++ err := ioutil.WriteFile(fileName, protoBytes, 0666) ++ if err != nil { ++ log.Exitf("Write %v failed", "PROTO" + string(cnt)) ++ } ++ cnt = cnt + 1 ++ } ++ } ++ } + } diff --git a/patches/gnmi_set.patch b/patches/gnmi_set.patch index dc913476..933e61d1 100644 --- a/patches/gnmi_set.patch +++ b/patches/gnmi_set.patch @@ -61,7 +61,25 @@ jsonFile := pathValuePair[1][1:] jsonConfig, err := ioutil.ReadFile(jsonFile) if err != nil { -@@ -144,8 +168,10 @@ +@@ -81,6 +105,17 @@ + JsonIetfVal: jsonConfig, + }, + } ++ } else if pathValuePair[1][0] == '$' { ++ protoFile := pathValuePair[1][1:] ++ protoConfig, err := ioutil.ReadFile(protoFile) ++ if err != nil { ++ log.Exitf("cannot read data from file %v", protoFile) ++ } ++ pbVal = &pb.TypedValue{ ++ Value: &pb.TypedValue_ProtoBytes{ ++ ProtoBytes: protoConfig, ++ }, ++ } + } else { + if strVal, err := strconv.Unquote(pathValuePair[1]); err == nil { + pbVal = &pb.TypedValue{ +@@ -144,8 +179,10 @@ } replaceList := buildPbUpdateList(replaceOpt) updateList := buildPbUpdateList(updateOpt) @@ -73,7 +91,7 @@ Delete: deleteList, Replace: replaceList, Update: updateList, -@@ -155,11 +181,17 @@ +@@ -155,11 +192,17 @@ utils.PrintProto(setRequest) cli := pb.NewGNMIClient(conn) diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 09a52d45..f74d5abe 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -111,7 +111,8 @@ type tablePath struct { tableKey string delimitor string field string - value string + jsonValue string + protoValue string index int operation int // path name to be used in json data which may be different diff --git a/sonic_data_client/mixed_db_client.go b/sonic_data_client/mixed_db_client.go index 084cb78b..0e5e679b 100644 --- a/sonic_data_client/mixed_db_client.go +++ b/sonic_data_client/mixed_db_client.go @@ -57,6 +57,7 @@ type MixedDbClient struct { prefix *gnmipb.Path paths []*gnmipb.Path pathG2S map[*gnmipb.Path][]tablePath + encoding gnmipb.Encoding q *queue.PriorityQueue channel chan struct{} target string @@ -219,7 +220,7 @@ func (c *MixedDbClient) DbDelTable(table string, key string) error { return nil } -func NewMixedDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path, origin string, zmqAddress string) (Client, error) { +func NewMixedDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path, origin string, encoding gnmipb.Encoding, zmqAddress string) (Client, error) { var err error // Testing program may ask to use redis local tcp connection @@ -231,6 +232,7 @@ func NewMixedDbClient(paths []*gnmipb.Path, prefix *gnmipb.Path, origin string, client.prefix = prefix client.target = "" client.origin = origin + client.encoding = encoding if prefix != nil { elems := prefix.GetElem() if elems != nil { @@ -318,20 +320,20 @@ func (c *MixedDbClient) populateDbtablePath(path *gnmipb.Path, value *gnmipb.Typ elems := fullPath.GetElem() if elems != nil { for i, elem := range elems { - // TODO: Usage of key field log.V(6).Infof("index %d elem : %#v %#v", i, elem.GetName(), elem.GetKey()) if i != 0 { buffer.WriteString(separator) } buffer.WriteString(elem.GetName()) stringSlice = append(stringSlice, elem.GetName()) + value, ok := elem.GetKey()["key"] + if ok { + buffer.WriteString(value) + stringSlice = append(stringSlice, value) + } } dbPath = buffer.String() } - value_str := "" - if value != nil { - value_str = string(value.GetJsonIetfVal()) - } tblPath.dbNamespace = dbNamespace tblPath.dbName = targetDbName @@ -339,9 +341,21 @@ func (c *MixedDbClient) populateDbtablePath(path *gnmipb.Path, value *gnmipb.Typ tblPath.delimitor = separator tblPath.operation = opRemove tblPath.index = -1 + tblPath.jsonValue = "" + tblPath.protoValue = "" if value != nil { tblPath.operation = opAdd - tblPath.value = value_str + jv := value.GetJsonIetfVal() + if jv != nil { + tblPath.jsonValue = string(jv) + } + pv := value.GetProtoBytes() + if pv != nil { + tblPath.protoValue = string(pv) + } + if jv == nil && pv == nil { + return fmt.Errorf("Unsupported TypedValue: %v", value) + } } var mappedKey string @@ -489,26 +503,63 @@ func (c *MixedDbClient) tableData2Msi(tblPath *tablePath, useKey bool, op *strin return err } - if tblPath.jsonTableKey != "" { // If jsonTableKey was prepared, use it - err = c.makeJSON_redis(msi, &tblPath.jsonTableKey, op, fv) - } else if (tblPath.tableKey != "" && !useKey) || tblPath.tableName == dbkey { - err = c.makeJSON_redis(msi, nil, op, fv) + if (tblPath.tableKey != "" && !useKey) || tblPath.tableName == dbkey { + if c.encoding == gnmipb.Encoding_JSON_IETF { + err = c.makeJSON_redis(msi, nil, op, fv) + if err != nil { + log.V(2).Infof("makeJSON err %s for fv %v", err, fv) + return err + } + } else if c.encoding == gnmipb.Encoding_PROTO { + value, ok := fv["pb"] + if ok { + (*msi)["pb"] = []byte(value) + } else { + return fmt.Errorf("No proto bytes found in redis %v", fv) + } + } } else { var key string // Split dbkey string into two parts and second part is key in table keys := strings.SplitN(dbkey, tblPath.delimitor, 2) key = keys[1] err = c.makeJSON_redis(msi, &key, op, fv) - } - if err != nil { - log.V(2).Infof("makeJSON err %s for fv %v", err, fv) - return err + if err != nil { + log.V(2).Infof("makeJSON err %s for fv %v", err, fv) + return err + } } log.V(6).Infof("Added idex %v fv %v ", idx, fv) } return nil } +func (c *MixedDbClient) msi2TypedValue(msi map[string]interface{}) (*gnmipb.TypedValue, error) { + if c.encoding == gnmipb.Encoding_JSON_IETF { + jv, err := emitJSON(&msi) + if err != nil { + log.V(2).Infof("emitJSON err %s for %v", err, msi) + return nil, fmt.Errorf("emitJSON err %s for %v", err, msi) + } + return &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_JsonIetfVal{ + JsonIetfVal: jv, + }}, nil + } else if c.encoding == gnmipb.Encoding_PROTO { + value, ok := msi["pb"] + if ok { + return &gnmipb.TypedValue{ + Value: &gnmipb.TypedValue_ProtoBytes{ + ProtoBytes: value.([]byte), + }}, nil + } else { + return nil, fmt.Errorf("No proto bytes found in msi %v", msi) + } + } else { + return nil, fmt.Errorf("Unknown encoding %v", c.encoding) + } +} + func (c *MixedDbClient) tableData2TypedValue(tblPaths []tablePath, op *string) (*gnmipb.TypedValue, error) { var useKey bool msi := make(map[string]interface{}) @@ -578,7 +629,7 @@ func (c *MixedDbClient) tableData2TypedValue(tblPaths []tablePath, op *string) ( return nil, err } } - return msi2TypedValue(msi) + return c.msi2TypedValue(msi) } func ConvertDbEntry(inputData map[string]interface{}) map[string]string { @@ -656,55 +707,45 @@ func (c *MixedDbClient) handleTableData(tblPaths []tablePath) error { } else if tblPath.operation == opAdd { if tblPath.tableKey != "" { // both table name and key provided - res, err = parseJson([]byte(tblPath.value)) - if err != nil { - return err - } - if vtable, ok := res.(map[string]interface{}); ok { - configMap := make(map[string]interface{}) - tableMap := make(map[string]interface{}) - tableMap[tblPath.tableKey] = vtable - configMap[tblPath.tableName] = tableMap - ietf_json_val, err := emitJSON(&configMap) + if len(tblPath.jsonValue) != 0 { + res, err = parseJson([]byte(tblPath.jsonValue)) if err != nil { - return fmt.Errorf("Translate to json failed!") + return err } - PyCodeInGo := fmt.Sprintf(PyCodeForYang, ietf_json_val) - err = RunPyCode(PyCodeInGo) - if err != nil { - return fmt.Errorf("Yang validation failed!") + if vtable, ok := res.(map[string]interface{}); ok { + outputData := ConvertDbEntry(vtable) + err = c.DbSetTable(tblPath.tableName, tblPath.tableKey, outputData) + if err != nil { + log.V(2).Infof("swsscommon update failed for %v, value %v", tblPath, outputData) + return err + } + } else { + return fmt.Errorf("Key %v: Unsupported value %v type %v", tblPath.tableKey, res, reflect.TypeOf(res)) } + } else if len(tblPath.protoValue) != 0 { + vtable := make(map[string]interface{}) + vtable["pb"] = tblPath.protoValue outputData := ConvertDbEntry(vtable) - c.DbDelTable(tblPath.tableName, tblPath.tableKey) err = c.DbSetTable(tblPath.tableName, tblPath.tableKey, outputData) if err != nil { log.V(2).Infof("swsscommon update failed for %v, value %v", tblPath, outputData) return err } } else { - return fmt.Errorf("Key %v: Unsupported value %v type %v", tblPath.tableKey, res, reflect.TypeOf(res)) + return fmt.Errorf("No valid value: %v", tblPath) } } else { - res, err = parseJson([]byte(tblPath.value)) + if len(tblPath.jsonValue) == 0 { + return fmt.Errorf("No valid value: %v", tblPath) + } + res, err = parseJson([]byte(tblPath.jsonValue)) if err != nil { return err } if vtable, ok := res.(map[string]interface{}); ok { - configMap := make(map[string]interface{}) - configMap[tblPath.tableName] = vtable - ietf_json_val, err := emitJSON(&configMap) - if err != nil { - return fmt.Errorf("Translate to json failed!") - } - PyCodeInGo := fmt.Sprintf(PyCodeForYang, ietf_json_val) - err = RunPyCode(PyCodeInGo) - if err != nil { - return fmt.Errorf("Yang validation failed!") - } for tableKey, tres := range vtable { if vt, ret := tres.(map[string]interface{}); ret { outputData := ConvertDbEntry(vt) - c.DbDelTable(tblPath.tableName, tableKey) err = c.DbSetTable(tblPath.tableName, tableKey, outputData) if err != nil { log.V(2).Infof("swsscommon update failed for %v, value %v", tblPath, outputData) @@ -1159,4 +1200,5 @@ func (c *MixedDbClient) SentOne(val *Value) { } func (c *MixedDbClient) FailedSend() { -} \ No newline at end of file +} + diff --git a/test/test_gnmi_appldb.py b/test/test_gnmi_appldb.py index 63ccc70e..7d5d9515 100644 --- a/test/test_gnmi_appldb.py +++ b/test/test_gnmi_appldb.py @@ -1,6 +1,6 @@ import json -from utils import gnmi_set, gnmi_get, gnmi_get_with_encoding +from utils import gnmi_set, gnmi_get, gnmi_get_with_encoding, gnmi_get_proto import pytest @@ -95,6 +95,42 @@ def test_gnmi_update_normal_01(self, test_data): break assert hit == True, 'No match for %s'%str(data['value']) + @pytest.mark.parametrize('test_data', test_data_update_normal) + def test_gnmi_update_normal_02(self, test_data): + clear_appl_db('DASH_QOS') + clear_appl_db('DASH_VNET') + update_list = [] + get_list = [] + for i, data in enumerate(test_data): + path = data['update_path'] + value = "" + file_name = 'update' + str(i) + file_object = open(file_name, 'w') + file_object.write(value) + file_object.close() + update_list.append(path + ':@./' + file_name) + + ret, msg = gnmi_set([], update_list, []) + assert ret != 0, "Invalid json ietf value" + + @pytest.mark.parametrize('test_data', test_data_update_normal) + def test_gnmi_update_normal_03(self, test_data): + clear_appl_db('DASH_QOS') + clear_appl_db('DASH_VNET') + update_list = [] + get_list = [] + for i, data in enumerate(test_data): + path = data['update_path'] + value = "x" + file_name = 'update' + str(i) + file_object = open(file_name, 'w') + file_object.write(value) + file_object.close() + update_list.append(path + ':@./' + file_name) + + ret, msg = gnmi_set([], update_list, []) + assert ret != 0, "Invalid json ietf value" + @pytest.mark.parametrize('test_data', test_data_update_normal) def test_gnmi_delete_normal_01(self, test_data): delete_list = [] @@ -321,7 +357,7 @@ def test_gnmi_invalid_target_03(self): def test_gnmi_invalid_encoding(self): path = '/sonic-db:APPL_DB/DASH_QOS' get_list = [path] - ret, msg_list = gnmi_get_with_encoding(get_list, "PROTO") + ret, msg_list = gnmi_get_with_encoding(get_list, "ASCII") assert ret != 0, 'Encoding is not supported' hit = False exp = 'unsupported encoding' @@ -331,3 +367,85 @@ def test_gnmi_invalid_encoding(self): break assert hit == True, 'No expected error: %s'%exp + def test_gnmi_update_proto_01(self): + proto_bytes = b"\n\x010\x12$b6d54023-5d24-47de-ae94-8afe693dd1fc\x1a\x17\n\x12\x12\x10\r\xc0-\xdd\x82\xa3\x88;\x0fP\x84<\xaakc\x16\x10\x80\x01\x1a\x17\n\x12\x12\x10-\x0e\xf2\x7f\n~c_\xd8\xb7\x10\x84\x81\xd6'|\x10\x80\x01\x1a\x17\n\x12\x12\x10\x1bV\x89\xc8JW\x06\xfb\xad\b*fN\x9e(\x17\x10\x80\x01\x1a\x17\n\x12\x12\x107\xf9\xbc\xc0\x8d!s\xccVT\x88\x00\xf8\x9c\xce\x90\x10\x80\x01\x1a\x17\n\x12\x12\x10\tEb\x11Mf]\x12\x17x\x99\x80\xea\xd1u\xb4\x10\x80\x01\x1a\x17\n\x12\x12\x10\x1f\xd3\x1c\x89\x99\x16\xe7\x18\x91^0\x81\xb1\x04\x8c\x1e\x10\x80\x01\x1a\x17\n\x12\x12\x10\x06\x9e55\xdb\xb5&\x93\x99\xfaC\x81\x16P\xdc\x1d\x10\x80\x01\x1a\x17\n\x12\x12\x10&]U\x96e4\xf4\xd2'&\x04i\xdf\x8dA\x9f\x10\x80\x01\x1a\x17\n\x12\x12\x108\xd5\xa3*\xe7\x80\xdc\x1e\x80f\x94\xb7\xb6\x86~\xcd\x10\x80\x01\x1a\x17\n\x12\x12\x101\xf0@F\nu+}\x1e\"\\\\\xdb\x01\xe3\x82\x10\x80\x01\"\x05vnet1\"\x05vnet2\"\x05vnet1\"\x05vnet2\"\x05vnet2\"\x05vnet1\"\x05vnet2\"\x05vnet2\"\x05vnet1\"\x05vnet1" + test_data = [ + { + 'update_path': '/sonic-db:APPL_DB/DASH_ROUTE_TABLE[key=F4939FEFC47E:20.2.2.0/24]', + 'get_path': '/sonic-db:APPL_DB/_DASH_ROUTE_TABLE[key=F4939FEFC47E:20.2.2.0/24]', + 'value': proto_bytes + }, + { + 'update_path': '/sonic-db:APPL_DB/DASH_ROUTE_TABLE[key=F4939FEFC47E:30.3.3.0/24]', + 'get_path': '/sonic-db:APPL_DB/_DASH_ROUTE_TABLE[key=F4939FEFC47E:30.3.3.0/24]', + 'value': proto_bytes + }, + { + 'update_path': '/sonic-db:APPL_DB/DASH_VNET_MAPPING_TABLE[key=Vnet2:20.2.2.2]', + 'get_path': '/sonic-db:APPL_DB/_DASH_VNET_MAPPING_TABLE[key=Vnet2:20.2.2.2]', + 'value': proto_bytes + } + ] + update_list = [] + for i, data in enumerate(test_data): + path = data['update_path'] + value = data['value'] + file_name = 'update{}.txt'.format(i) + file_object = open(file_name, 'wb') + file_object.write(value) + file_object.close() + update_list.append(path + ':$./' + file_name) + + ret, msg = gnmi_set([], update_list, []) + assert ret == 0, msg + for i, data in enumerate(test_data): + path = data['get_path'] + file_name = 'get{}.txt'.format(i) + ret, msg = gnmi_get_proto([path], [file_name]) + assert ret == 0, msg + result_bytes = open(file_name, 'rb').read() + assert proto_bytes == result_bytes, 'get proto not equal to update proto' + + def test_gnmi_update_proto_02(self): + update_path = '/sonic-db:APPL_DB/DASH_QOS' + get_path = '/sonic-db:APPL_DB/_DASH_QOS[key=qos1]' + value = { + 'qos_01': {'bw': '54321', 'cps': '1000', 'flows': '300'}, + 'qos_02': {'bw': '6000', 'cps': '200', 'flows': '101'} + } + update_list = [] + text = json.dumps(value) + file_name = 'update.txt' + file_object = open(file_name, 'w') + file_object.write(text) + file_object.close() + update_list = [update_path + ':@./' + file_name] + + ret, msg = gnmi_set([], update_list, []) + assert ret == 0, msg + + get_list = [get_path] + file_list = ['get_proto.txt'] + ret, msg_list = gnmi_get_proto(get_list, file_list) + assert ret != 0, 'Can not get result with proto encoding' + + def test_gnmi_delete_proto_01(self): + test_data = [ + { + 'update_path': '/sonic-db:APPL_DB/DASH_ROUTE_TABLE/F4939FEFC47E:20.2.2.0\\\\/24', + }, + { + 'update_path': '/sonic-db:APPL_DB/DASH_ROUTE_TABLE/F4939FEFC47E:30.3.3.0\\\\/24', + }, + { + 'update_path': '/sonic-db:APPL_DB/DASH_VNET_MAPPING_TABLE/Vnet2:20.2.2.2', + } + ] + delete_list = [] + for i, data in enumerate(test_data): + path = data['update_path'] + delete_list.append(path) + + ret, msg = gnmi_set(delete_list, [], []) + assert ret == 0, msg + diff --git a/test/utils.py b/test/utils.py index 38966e7e..6325206a 100644 --- a/test/utils.py +++ b/test/utils.py @@ -99,6 +99,20 @@ def gnmi_get_with_encoding(path_list, encoding): return -1, [msg] return ret, [msg] +def gnmi_get_proto(path_list, file_list): + path = os.getcwd() + cmd = path + '/build/bin/gnmi_get ' + cmd += '-insecure -username admin -password sonicadmin ' + cmd += '-target_addr 127.0.0.1:8080 ' + cmd += '-alsologtostderr ' + cmd += '-encoding PROTO ' + for path in path_list: + cmd += " -xpath " + path + for file in file_list: + cmd += " -proto_file " + file + ret, msg = run_cmd(cmd) + return ret, msg + def gnmi_get_with_password(path_list, user, password): path = os.getcwd() cmd = path + '/build/bin/gnmi_get '