From 80067ec2623e0d6b18006bb3fad554a3526a9d48 Mon Sep 17 00:00:00 2001 From: wumiao Date: Thu, 17 Oct 2024 16:14:12 -0400 Subject: [PATCH 01/11] Fix a panic by gnmi subscribe with invalid xpath --- gnmi_server/client_subscribe.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gnmi_server/client_subscribe.go b/gnmi_server/client_subscribe.go index bf791e79..2207bd30 100644 --- a/gnmi_server/client_subscribe.go +++ b/gnmi_server/client_subscribe.go @@ -179,12 +179,13 @@ func (c *Client) Run(stream gnmipb.GNMI_SubscribeServer) (err error) { /* For any other target or no target create new Transl Client. */ dc, err = sdc.NewTranslClient(prefix, paths, ctx, extensions, sdc.TranslWildcardOption{}) } - defer dc.Close() if err != nil { return grpc.Errorf(codes.NotFound, "%v", err) } + defer dc.Close() + switch mode { case gnmipb.SubscriptionList_STREAM: c.stop = make(chan struct{}, 1) From c702d319b0e71213ca5e7e52a00c322f1df2ae5a Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Thu, 31 Oct 2024 17:11:59 +0000 Subject: [PATCH 02/11] Add build artifacts to gitignore. Also clean them up with documentation. --- .gitignore | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d70506f2..3c42991f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,26 @@ +# Build directory build/ + +# Debian packaging files debian/.debhelper/ debian/files debian/sonic-telemetry.debhelper.log debian/sonic-telemetry.substvars debian/sonic-telemetry/ -vendor -src -cvl -translib +debian/sonic-gnmi.debhelper.log +debian/sonic-gnmi.substvars +debian/sonic-gnmi/ + +# Vendor directory +vendor/ + +# Source directories +src/ +cvl/ +translib/ + +# SWSS common generated files +swsscommon/swsscommon.go +swsscommon/swsscommon.i +swsscommon/swsscommon_wrap.cxx +swsscommon/swsscommon_wrap.h \ No newline at end of file From 2846d28717a381d2ffede75479e1c8c043b942ba Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Fri, 1 Nov 2024 19:51:16 +0000 Subject: [PATCH 03/11] Add dbus image counter --- common_utils/context.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common_utils/context.go b/common_utils/context.go index a9059f4a..bbf7665b 100644 --- a/common_utils/context.go +++ b/common_utils/context.go @@ -6,11 +6,10 @@ import ( "sync/atomic" ) - // AuthInfo holds data about the authenticated user type AuthInfo struct { // Username - User string + User string AuthEnabled bool // Roles Roles []string @@ -37,6 +36,7 @@ const requestContextKey contextkey = 0 var requestCounter uint64 type CounterType int + const ( GNMI_GET CounterType = iota GNMI_GET_FAIL @@ -54,6 +54,8 @@ const ( DBUS_STOP_SERVICE DBUS_RESTART_SERVICE DBUS_FILE_STAT + DBUS_IMAGE_DOWNLOAD + DBUS_IMAGE_INSTALL COUNTER_SIZE ) @@ -91,6 +93,10 @@ func (c CounterType) String() string { return "DBUS restart service" case DBUS_FILE_STAT: return "DBUS file stat" + case DBUS_IMAGE_DOWNLOAD: + return "DBUS image download" + case DBUS_IMAGE_INSTALL: + return "DBUS image install" default: return "" } @@ -98,7 +104,6 @@ func (c CounterType) String() string { var globalCounters [COUNTER_SIZE]uint64 - // GetContext function returns the RequestContext object for a // gRPC request. RequestContext is maintained as a context value of // the request. Creates a new RequestContext object is not already @@ -134,4 +139,3 @@ func IncCounter(cnt CounterType) { atomic.AddUint64(&globalCounters[cnt], 1) SetMemCounters(&globalCounters) } - From 2a11f04d4ab5350b874652585e21d561c9c0caf0 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Fri, 1 Nov 2024 20:08:06 +0000 Subject: [PATCH 04/11] DBUS client code and unit test. --- sonic_service_client/dbus_client.go | 31 ++++- sonic_service_client/dbus_client_test.go | 164 ++++++++++++++++++++++- 2 files changed, 188 insertions(+), 7 deletions(-) diff --git a/sonic_service_client/dbus_client.go b/sonic_service_client/dbus_client.go index 48291570..a7868867 100644 --- a/sonic_service_client/dbus_client.go +++ b/sonic_service_client/dbus_client.go @@ -1,11 +1,12 @@ package host_service import ( - "time" "fmt" "reflect" - log "github.com/golang/glog" + "time" + "github.com/godbus/dbus/v5" + log "github.com/golang/glog" "github.com/sonic-net/sonic-gnmi/common_utils" ) @@ -14,18 +15,20 @@ type Service interface { ConfigSave(fileName string) error ApplyPatchYang(fileName string) error ApplyPatchDb(fileName string) error - CreateCheckPoint(cpName string) error + CreateCheckPoint(cpName string) error DeleteCheckPoint(cpName string) error StopService(service string) error RestartService(service string) error GetFileStat(path string) (map[string]string, error) + DownloadImage(url string, save_as string) error + InstallImage(where string) error } type DbusClient struct { busNamePrefix string busPathPrefix string intNamePrefix string - channel chan struct{} + channel chan struct{} } func NewDbusClient() (Service, error) { @@ -191,3 +194,23 @@ func (c *DbusClient) GetFileStat(path string) (map[string]string, error) { data, _ := result.(map[string]string) return data, nil } + +func (c *DbusClient) DownloadImage(url string, save_as string) error { + common_utils.IncCounter(common_utils.DBUS_IMAGE_DOWNLOAD) + modName := "image_service" + busName := c.busNamePrefix + modName + busPath := c.busPathPrefix + modName + intName := c.intNamePrefix + modName + ".download" + _, err := DbusApi(busName, busPath, intName /*timeout=*/, 900, url, save_as) + return err +} + +func (c *DbusClient) InstallImage(where string) error { + common_utils.IncCounter(common_utils.DBUS_IMAGE_INSTALL) + modName := "image_service" + busName := c.busNamePrefix + modName + busPath := c.busPathPrefix + modName + intName := c.intNamePrefix + modName + ".install" + _, err := DbusApi(busName, busPath, intName /*timeout=*/, 900, where) + return err +} diff --git a/sonic_service_client/dbus_client_test.go b/sonic_service_client/dbus_client_test.go index aae99608..942bbe2e 100644 --- a/sonic_service_client/dbus_client_test.go +++ b/sonic_service_client/dbus_client_test.go @@ -1,8 +1,8 @@ package host_service import ( - "testing" "reflect" + "testing" "github.com/agiledragon/gomonkey/v2" "github.com/godbus/dbus/v5" @@ -27,7 +27,7 @@ func TestGetFileStat(t *testing.T) { "size": "1024", "umask": "022", } - + // Mocking the DBus API to return the expected result mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { return &dbus.Conn{}, nil @@ -65,7 +65,7 @@ func TestGetFileStat(t *testing.T) { func TestGetFileStatNegative(t *testing.T) { errMsg := "This is the mock error message" - // Mocking the DBus API to return an error + // Mocking the DBus API to return an error mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { return &dbus.Conn{}, nil }) @@ -487,3 +487,161 @@ func TestDeleteCheckPointNegative(t *testing.T) { t.Errorf("Wrong error: %v", err) } } + +func TestDownloadImageSuccess(t *testing.T) { + url := "http://example/sonic-img" + save_as := "/tmp/sonic-img" + mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { + return &dbus.Conn{}, nil + }) + defer mock1.Reset() + 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 { + if method != "org.SONiC.HostService.image_service.download" { + t.Errorf("Wrong method: %v", method) + } + if len(args) != 2 { + t.Errorf("Wrong number of arguments: %v", len(args)) + } + if args[0] != url { + t.Errorf("Wrong URL: %v", args[0]) + } + if args[1] != save_as { + t.Errorf("Wrong save_as: %v", args[1]) + } + ret := &dbus.Call{} + ret.Err = nil + ret.Body = make([]interface{}, 2) + ret.Body[0] = int32(0) + ch <- ret + return &dbus.Call{} + }) + defer mock2.Reset() + + client, err := NewDbusClient() + if err != nil { + t.Errorf("NewDbusClient failed: %v", err) + } + err = client.DownloadImage(url, save_as) + if err != nil { + t.Errorf("Download should pass: %v", err) + } +} + +func TestDownloadImageFail(t *testing.T) { + url := "http://example/sonic-img" + save_as := "/tmp/sonic-img" + err_msg := "This is the mock error message" + + mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { + return &dbus.Conn{}, nil + }) + defer mock1.Reset() + 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 { + if method != "org.SONiC.HostService.image_service.download" { + t.Errorf("Wrong method: %v", method) + } + if len(args) != 2 { + t.Errorf("Wrong number of arguments: %v", len(args)) + } + if args[0] != url { + t.Errorf("Wrong URL: %v", args[0]) + } + if args[1] != save_as { + t.Errorf("Wrong save_as: %v", args[1]) + } + ret := &dbus.Call{} + ret.Err = nil + ret.Body = make([]interface{}, 2) + ret.Body[0] = int32(1) + ret.Body[1] = err_msg + ch <- ret + return &dbus.Call{} + }) + defer mock2.Reset() + + client, err := NewDbusClient() + if err != nil { + t.Errorf("NewDbusClient failed: %v", err) + } + err = client.DownloadImage(url, save_as) + if err == nil { + t.Errorf("Download should fail") + } + if err.Error() != err_msg { + t.Errorf("Expected error message '%s' but got '%v'", err_msg, err) + } +} +func TestInstallImageSuccess(t *testing.T) { + where := "/tmp/sonic-img" + mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { + return &dbus.Conn{}, nil + }) + defer mock1.Reset() + 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 { + if method != "org.SONiC.HostService.image_service.install" { + t.Errorf("Wrong method: %v", method) + } + if len(args) != 1 { + t.Errorf("Wrong number of arguments: %v", len(args)) + } + if args[0] != where { + t.Errorf("Wrong where: %v", args[0]) + } + ret := &dbus.Call{} + ret.Err = nil + ret.Body = make([]interface{}, 2) + ret.Body[0] = int32(0) + ch <- ret + return &dbus.Call{} + }) + defer mock2.Reset() + + client, err := NewDbusClient() + if err != nil { + t.Errorf("NewDbusClient failed: %v", err) + } + err = client.InstallImage(where) + if err != nil { + t.Errorf("InstallImage should pass: %v", err) + } +} +func TestInstallImageFail(t *testing.T) { + where := "/tmp/sonic-img" + err_msg := "This is the mock error message" + + mock1 := gomonkey.ApplyFunc(dbus.SystemBus, func() (conn *dbus.Conn, err error) { + return &dbus.Conn{}, nil + }) + defer mock1.Reset() + 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 { + if method != "org.SONiC.HostService.image_service.install" { + t.Errorf("Wrong method: %v", method) + } + if len(args) != 1 { + t.Errorf("Wrong number of arguments: %v", len(args)) + } + if args[0] != where { + t.Errorf("Wrong where: %v", args[0]) + } + ret := &dbus.Call{} + ret.Err = nil + ret.Body = make([]interface{}, 2) + ret.Body[0] = int32(1) + ret.Body[1] = err_msg + ch <- ret + return &dbus.Call{} + }) + defer mock2.Reset() + + client, err := NewDbusClient() + if err != nil { + t.Errorf("NewDbusClient failed: %v", err) + } + err = client.InstallImage(where) + if err == nil { + t.Errorf("InstallImage should fail") + } + if err.Error() != err_msg { + t.Errorf("Expected error message '%s' but got '%v'", err_msg, err) + } +} From e8449250bec233c81cf4b6aa324c26da7fea5732 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam <163894573+vvolam@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:50:01 -0700 Subject: [PATCH 05/11] Add support for RebootMethod_HALT for Reboot API (#286) Why I did it Add support for HALT reboot method for Reboot gNOI API How I did it Implement changes for HaltSystem() function to be called when HALT reboot method is invoked. How to verify it Unit tests --- common_utils/context.go | 3 ++ gnmi_server/gnoi.go | 48 ++++++++++++++++++++++------- sonic_service_client/dbus_client.go | 19 ++++++++++++ test/test_gnoi.py | 13 +++++++- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/common_utils/context.go b/common_utils/context.go index a9059f4a..09bff486 100644 --- a/common_utils/context.go +++ b/common_utils/context.go @@ -54,6 +54,7 @@ const ( DBUS_STOP_SERVICE DBUS_RESTART_SERVICE DBUS_FILE_STAT + DBUS_HALT_SYSTEM COUNTER_SIZE ) @@ -91,6 +92,8 @@ func (c CounterType) String() string { return "DBUS restart service" case DBUS_FILE_STAT: return "DBUS file stat" + case DBUS_HALT_SYSTEM: + return "DBUS halt system" default: return "" } diff --git a/gnmi_server/gnoi.go b/gnmi_server/gnoi.go index f11a9a81..4c3aad6c 100644 --- a/gnmi_server/gnoi.go +++ b/gnmi_server/gnoi.go @@ -139,6 +139,20 @@ func (srv *SystemServer) KillProcess(ctx context.Context, req *gnoi_system_pb.Ki return &resp, nil } +func HaltSystem() error { + sc,err := ssc.NewDbusClient() + if err != nil { + return err + } + + log.V(2).Infof("Halting the system..") + err = sc.HaltSystem() + if err != nil { + log.V(2).Infof("Failed to Halt the system %v", err); + } + return err +} + func RebootSystem(fileName string) error { log.V(2).Infof("Rebooting with %s...", fileName) sc, err := ssc.NewDbusClient() @@ -158,18 +172,30 @@ func (srv *SystemServer) Reboot(ctx context.Context, req *gnoi_system_pb.RebootR } log.V(1).Info("gNOI: Reboot") log.V(1).Info("Request:", req) - log.V(1).Info("Reboot system now, delay is ignored...") - // TODO: Support GNOI reboot delay - // Delay in nanoseconds before issuing reboot. - // https://github.com/openconfig/gnoi/blob/master/system/system.proto#L102-L115 - config_db_json, err := io.ReadFile(fileName) - if errors.Is(err, os.ErrNotExist) { - fileName = "" - } - err = RebootSystem(string(config_db_json)) - if err != nil { - return nil, err + + // Check the reboot type + switch req.GetMethod() { + case gnoi_system_pb.RebootMethod_HALT: + log.V(1).Info("Reboot method is HALT. Halting the system...") + err = HaltSystem() + if err != nil { + return nil, err + } + default: + log.V(1).Info("Reboot system now, delay is ignored...") + // TODO: Support GNOI reboot delay + // Delay in nanoseconds before issuing reboot. + // https://github.com/openconfig/gnoi/blob/master/system/system.proto#L102-L115 + config_db_json, err := io.ReadFile(fileName) + if errors.Is(err, os.ErrNotExist) { + fileName = "" + } + err = RebootSystem(string(config_db_json)) + if err != nil { + return nil, err + } } + var resp gnoi_system_pb.RebootResponse return &resp, nil } diff --git a/sonic_service_client/dbus_client.go b/sonic_service_client/dbus_client.go index 48291570..51777099 100644 --- a/sonic_service_client/dbus_client.go +++ b/sonic_service_client/dbus_client.go @@ -19,6 +19,7 @@ type Service interface { StopService(service string) error RestartService(service string) error GetFileStat(path string) (map[string]string, error) + HaltSystem() error } type DbusClient struct { @@ -191,3 +192,21 @@ func (c *DbusClient) GetFileStat(path string) (map[string]string, error) { data, _ := result.(map[string]string) return data, nil } + +func (c *DbusClient) HaltSystem() error { + // Increment the counter for the DBUS_HALT_SYSTEM event + common_utils.IncCounter(common_utils.DBUS_HALT_SYSTEM) + + // Set the module name and update the D-Bus properties + modName := "systemd" + busName := c.busNamePrefix + modName + busPath := c.busPathPrefix + modName + intName := c.intNamePrefix + modName + ".execute_reboot" + + //Set the method to HALT(3) the system + const RebootMethod_HALT = 3 + + // Invoke the D-Bus API to execute the halt command + _, err := DbusApi(busName, busPath, intName, 10, RebootMethod_HALT) + return err +} diff --git a/test/test_gnoi.py b/test/test_gnoi.py index 61b7c067..f8ceccf3 100644 --- a/test/test_gnoi.py +++ b/test/test_gnoi.py @@ -21,6 +21,17 @@ def test_gnoi_reboot(self): assert ret == 0, 'Fail to read counter' assert new_cnt == old_cnt+1, 'DBUS API is not invoked' + def test_gnoi_reboot_halt(self): + ret, old_cnt = gnmi_dump('DBUS halt system') + assert ret == 0, 'Fail to read counter' + + ret, msg = gnoi_reboot(3, 0, 'Test halt system') + assert ret == 0, msg + + ret, new_cnt = gnmi_dump('DBUS halt system') + assert ret == 0, 'Fail to read counter' + assert new_cnt == old_cnt+1, 'DBUS API is not invoked' + def test_gnoi_rebootstatus(self): ret, msg = gnoi_rebootstatus() assert ret != 0, 'RebootStatus should fail' + msg @@ -74,4 +85,4 @@ def test_gnoi_restartprocess_invalid(self): ret, new_cnt = gnmi_dump('DBUS restart service') assert ret == 0, 'Fail to read counter' - assert new_cnt == old_cnt, 'DBUS API invoked unexpectedly' \ No newline at end of file + assert new_cnt == old_cnt, 'DBUS API invoked unexpectedly' From d62df54d549737722f0bc48074611b914c0d1c14 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Wed, 6 Nov 2024 22:21:45 +0000 Subject: [PATCH 06/11] format fix. --- common_utils/context.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common_utils/context.go b/common_utils/context.go index a57fef73..4e19a871 100644 --- a/common_utils/context.go +++ b/common_utils/context.go @@ -54,7 +54,7 @@ const ( DBUS_STOP_SERVICE DBUS_RESTART_SERVICE DBUS_FILE_STAT - DBUS_HALT_SYSTEM + DBUS_HALT_SYSTEM DBUS_IMAGE_DOWNLOAD DBUS_IMAGE_INSTALL COUNTER_SIZE @@ -94,7 +94,7 @@ func (c CounterType) String() string { return "DBUS restart service" case DBUS_FILE_STAT: return "DBUS file stat" - case DBUS_HALT_SYSTEM: + case DBUS_HALT_SYSTEM: return "DBUS halt system" case DBUS_IMAGE_DOWNLOAD: return "DBUS image download" From e784b6f2c67e9464c865311439dfe03a89ee4b9b Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:35:12 -0800 Subject: [PATCH 07/11] Fix Wildcard entries to return empty data instead of invalid path (#299) * Fix Wildcard entries to return empty data instead of invalid path * Add existing table test * Add check for empty json in test --- gnmi_server/server_test.go | 193 ++++++++++++++++++++++++++++++++- sonic_data_client/db_client.go | 10 +- testdata/EMPTY_JSON.txt | 1 + 3 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 testdata/EMPTY_JSON.txt diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index bee65d08..b97e2f63 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -1297,11 +1297,11 @@ func runGnmiTestGet(t *testing.T, namespace string) { }, { desc: "Get valid but non-existing node", - pathTarget: "COUNTERS_DB", + pathTarget: stateDBPath, textPbPath: ` - elem: - `, - wantRetCode: codes.NotFound, + elem: + `, + wantRetCode: codes.OK, }, { desc: "Get COUNTERS_PORT_NAME_MAP", pathTarget: "COUNTERS_DB", @@ -3487,6 +3487,191 @@ func TestClientConnections(t *testing.T) { } } +func TestWildcardTableNoError(t *testing.T) { + s := createServer(t, 8081) + go runServer(t, s) + defer s.ForceStop() + + fileName := "../testdata/NEIGH_STATE_TABLE_MAP.txt" + neighStateTableByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + + var neighStateTableJson interface{} + json.Unmarshal(neighStateTableByte, &neighStateTableJson) + + tests := []struct { + desc string + q client.Query + wantNoti []client.Notification + poll int + }{ + { + desc: "poll query for NEIGH_STATE_TABLE", + poll: 1, + q: client.Query{ + Target: "STATE_DB", + Type: client.Poll, + Queries: []client.Path{{"NEIGH_STATE_TABLE"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + wantNoti: []client.Notification{ + client.Update{Path: []string{"NEIGH_STATE_TABLE"}, TS: time.Unix(0, 200), Val: neighStateTableJson}, + client.Update{Path: []string{"NEIGH_STATE_TABLE"}, TS: time.Unix(0, 200), Val: neighStateTableJson}, + }, + }, + } + namespace, _ := sdcfg.GetDbDefaultNamespace() + prepareStateDb(t, namespace) + var mutexNoti sync.Mutex + for _, tt := range tests { + + t.Run(tt.desc, func(t *testing.T) { + q := tt.q + q.Addrs = []string{"127.0.0.1:8081"} + c := client.New() + var gotNoti []client.Notification + q.NotificationHandler = func(n client.Notification) error { + mutexNoti.Lock() + if nn, ok := n.(client.Update); ok { + nn.TS = time.Unix(0, 200) + gotNoti = append(gotNoti, nn) + } + mutexNoti.Unlock() + return nil + } + + wg := new(sync.WaitGroup) + wg.Add(1) + + go func() { + defer wg.Done() + if err := c.Subscribe(context.Background(), q); err != nil { + t.Errorf("c.Subscribe(): got error %v, expected nil", err) + } + }() + + wg.Wait() + + for i := 0; i < tt.poll; i++ { + if err := c.Poll(); err != nil { + t.Errorf("c.Poll(): got error %v, expected nil", err) + } + } + + mutexNoti.Lock() + + if len(gotNoti) == 0 { + t.Errorf("expected non zero notifications") + } + + if diff := pretty.Compare(tt.wantNoti, gotNoti); diff != "" { + t.Log("\n Want: \n", tt.wantNoti) + t.Log("\n Got: \n", gotNoti) + t.Errorf("unexpected updates: \n%s", diff) + } + + mutexNoti.Unlock() + + c.Close() + }) + } +} + +func TestNonExistentTableNoError(t *testing.T) { + s := createServer(t, 8081) + go runServer(t, s) + defer s.ForceStop() + + fileName := "../testdata/EMPTY_JSON.txt" + transceiverDomSensorTableByte, err := ioutil.ReadFile(fileName) + if err != nil { + t.Fatalf("read file %v err: %v", fileName, err) + } + + var transceiverDomSensorTableJson interface{} + json.Unmarshal(transceiverDomSensorTableByte, &transceiverDomSensorTableJson) + + tests := []struct { + desc string + q client.Query + wantNoti []client.Notification + poll int + }{ + { + desc: "poll query for TRANSCEIVER_DOM_SENSOR", + poll: 1, + q: client.Query{ + Target: "STATE_DB", + Type: client.Poll, + Queries: []client.Path{{"TRANSCEIVER_DOM_SENSOR"}}, + TLS: &tls.Config{InsecureSkipVerify: true}, + }, + wantNoti: []client.Notification{ + client.Update{Path: []string{"TRANSCEIVER_DOM_SENSOR"}, TS: time.Unix(0, 200), Val: transceiverDomSensorTableJson}, + client.Update{Path: []string{"TRANSCEIVER_DOM_SENSOR"}, TS: time.Unix(0, 200), Val: transceiverDomSensorTableJson}, + }, + }, + } + namespace, _ := sdcfg.GetDbDefaultNamespace() + prepareStateDb(t, namespace) + var mutexNoti sync.Mutex + + for _, tt := range tests { + prepareStateDb(t, namespace) + t.Run(tt.desc, func(t *testing.T) { + q := tt.q + q.Addrs = []string{"127.0.0.1:8081"} + c := client.New() + var gotNoti []client.Notification + q.NotificationHandler = func(n client.Notification) error { + mutexNoti.Lock() + if nn, ok := n.(client.Update); ok { + nn.TS = time.Unix(0, 200) + gotNoti = append(gotNoti, nn) + } + mutexNoti.Unlock() + return nil + } + + wg := new(sync.WaitGroup) + wg.Add(1) + + go func() { + defer wg.Done() + if err := c.Subscribe(context.Background(), q); err != nil { + t.Errorf("c.Subscribe(): got error %v, expected nil", err) + } + }() + + wg.Wait() + + for i := 0; i < tt.poll; i++ { + if err := c.Poll(); err != nil { + t.Errorf("c.Poll(): got error %v, expected nil", err) + } + } + + mutexNoti.Lock() + + if len(gotNoti) == 0 { + t.Errorf("expected non zero notifications") + } + + if diff := pretty.Compare(tt.wantNoti, gotNoti); diff != "" { + t.Log("\n Want: \n", tt.wantNoti) + t.Log("\n Got: \n", gotNoti) + t.Errorf("unexpected updates: \n%s", diff) + } + + mutexNoti.Unlock() + + c.Close() + }) + } +} + func TestConnectionDataSet(t *testing.T) { s := createServer(t, 8081) go runServer(t, s) diff --git a/sonic_data_client/db_client.go b/sonic_data_client/db_client.go index 99f58a8a..cb94d1b0 100644 --- a/sonic_data_client/db_client.go +++ b/sonic_data_client/db_client.go @@ -670,11 +670,13 @@ func populateDbtablePath(prefix, path *gnmipb.Path, pathG2S *map[*gnmipb.Path][] // <5> DB Table Key Key Field switch len(stringSlice) { case 2: // only table name provided - res, err := redisDb.Keys(tblPath.tableName + "*").Result() - if err != nil || len(res) < 1 { - log.V(2).Infof("Invalid db table Path %v %v", target, dbPath) - return fmt.Errorf("Failed to find %v %v %v %v", target, dbPath, err, res) + wildcardTableName := tblPath.tableName + "*" + log.V(6).Infof("Fetching all keys for %v with table name %s", target, wildcardTableName) + res, err := redisDb.Keys(wildcardTableName).Result() + if err != nil { + return fmt.Errorf("redis Keys op failed for %v %v, got err %v %v", target, dbPath, err, res) } + log.V(6).Infof("Result of keys operation for %v %v, got %v", target, dbPath, res) tblPath.tableKey = "" case 3: // Third element could be table key; or field name in which case table name itself is the key too n, err := redisDb.Exists(tblPath.tableName + tblPath.delimitor + mappedKey).Result() diff --git a/testdata/EMPTY_JSON.txt b/testdata/EMPTY_JSON.txt new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/testdata/EMPTY_JSON.txt @@ -0,0 +1 @@ +{} From 883d617a9338fb10210990682116be13e96407c0 Mon Sep 17 00:00:00 2001 From: ganglv <88995770+ganglyu@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:00:07 +0800 Subject: [PATCH 08/11] Update dbus timeout to 10 minutes (#326) Why I did it We found that GCU takes about 10 minutes to update ACL rules How I did it Update dbus timeout to 10 minutes so that we can use GNMI to update ACL rules. How to verify it Run GNMI unit test and end to end test --- sonic_service_client/dbus_client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonic_service_client/dbus_client.go b/sonic_service_client/dbus_client.go index 51777099..d54dda13 100644 --- a/sonic_service_client/dbus_client.go +++ b/sonic_service_client/dbus_client.go @@ -125,7 +125,7 @@ func (c *DbusClient) ApplyPatchYang(patch string) error { busName := c.busNamePrefix + modName busPath := c.busPathPrefix + modName intName := c.intNamePrefix + modName + ".apply_patch_yang" - _, err := DbusApi(busName, busPath, intName, 240, patch) + _, err := DbusApi(busName, busPath, intName, 600, patch) return err } @@ -135,7 +135,7 @@ func (c *DbusClient) ApplyPatchDb(patch string) error { busName := c.busNamePrefix + modName busPath := c.busPathPrefix + modName intName := c.intNamePrefix + modName + ".apply_patch_db" - _, err := DbusApi(busName, busPath, intName, 240, patch) + _, err := DbusApi(busName, busPath, intName, 600, patch) return err } From e0f09241f7ac15135cdc3ea0f16e7f217d1dd4b7 Mon Sep 17 00:00:00 2001 From: Hua Liu <58683130+liuh-80@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:30:20 +0800 Subject: [PATCH 09/11] Install advancetls package to support crl. (#318) Install advancetls package to support crl. #### Why I did it Support certificate revocation list. #### How I did it Install advancetls package to support crl. Improve make file. #### How to verify it Manually test. Add new UT. #### Work item tracking Microsoft ADO (number only): 27146924 #### Which release branch to backport (provide reason below if selected) - [ ] 201811 - [ ] 201911 - [ ] 202006 - [ ] 202012 - [ ] 202106 - [ ] 202111 #### Description for the changelog Upgrade crypto package to v0.24.0 to support crl #### Link to config_db schema for YANG module changes #### A picture of a cute animal (not mandatory but encouraged) --- Makefile | 47 ++++++--- go.mod | 24 +++-- go.sum | 97 ++++++++++++------- ...02-Fix-advance-tls-build-with-go-119.patch | 33 +++++++ 4 files changed, 145 insertions(+), 56 deletions(-) create mode 100644 patches/0002-Fix-advance-tls-build-with-go-119.patch diff --git a/Makefile b/Makefile index c711ee05..039fed73 100644 --- a/Makefile +++ b/Makefile @@ -49,18 +49,18 @@ go.mod: $(GO_DEPS): go.mod $(PATCHES) swsscommon_wrap $(GO) mod vendor - $(GO) mod download golang.org/x/crypto@v0.0.0-20191206172530-e9b2fee46413 $(GO) mod download github.com/jipanyang/gnxi@v0.0.0-20181221084354-f0a90cca6fd0 - cp -r $(GOPATH)/pkg/mod/golang.org/x/crypto@v0.0.0-20191206172530-e9b2fee46413/* vendor/golang.org/x/crypto/ cp -r $(GOPATH)/pkg/mod/github.com/jipanyang/gnxi@v0.0.0-20181221084354-f0a90cca6fd0/* vendor/github.com/jipanyang/gnxi/ + +# Apply patch from sonic-mgmt-common, ignore glog.patch because glog version changed + sed -i 's/patch -d $${DEST_DIR}\/github.com\/golang\/glog/\#patch -d $${DEST_DIR}\/github.com\/golang\/glog/g' $(MGMT_COMMON_DIR)/patches/apply.sh $(MGMT_COMMON_DIR)/patches/apply.sh vendor + sed -i 's/#patch -d $${DEST_DIR}\/github.com\/golang\/glog/patch -d $${DEST_DIR}\/github.com\/golang\/glog/g' $(MGMT_COMMON_DIR)/patches/apply.sh + chmod -R u+w vendor - patch -d vendor -p0 < patches/gnmi_cli.all.patch - patch -d vendor -p0 < patches/gnmi_set.patch - patch -d vendor -p0 < patches/gnmi_get.patch patch -d vendor -p0 < patches/gnmi_path.patch patch -d vendor -p0 < patches/gnmi_xpath.patch - git apply patches/0001-Updated-to-filter-and-write-to-file.patch + touch $@ go-deps: $(GO_DEPS) @@ -69,14 +69,14 @@ go-deps-clean: $(RM) -r vendor sonic-gnmi: $(GO_DEPS) +# advancetls 1.0.0 release need following patch to build by go-1.19 +# patch -d vendor -p0 < patches/0002-Fix-advance-tls-build-with-go-119.patch +# build service first which depends on advancetls ifeq ($(CROSS_BUILD_ENVIRON),y) $(GO) build -o ${GOBIN}/telemetry -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/telemetry ifneq ($(ENABLE_DIALOUT_VALUE),0) $(GO) build -o ${GOBIN}/dialout_client_cli -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/dialout/dialout_client_cli endif - $(GO) build -o ${GOBIN}/gnmi_get -mod=vendor github.com/jipanyang/gnxi/gnmi_get - $(GO) build -o ${GOBIN}/gnmi_set -mod=vendor github.com/jipanyang/gnxi/gnmi_set - $(GO) build -o ${GOBIN}/gnmi_cli -mod=vendor github.com/openconfig/gnmi/cmd/gnmi_cli $(GO) build -o ${GOBIN}/gnoi_client -mod=vendor github.com/sonic-net/sonic-gnmi/gnoi_client $(GO) build -o ${GOBIN}/gnmi_dump -mod=vendor github.com/sonic-net/sonic-gnmi/gnmi_dump else @@ -84,13 +84,38 @@ else ifneq ($(ENABLE_DIALOUT_VALUE),0) $(GO) install -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/dialout/dialout_client_cli endif + $(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnoi_client + $(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnmi_dump +endif + +# download and apply patch for gnmi client, which will break advancetls +# backup crypto and gnxi + mkdir backup_crypto + cp -r vendor/golang.org/x/crypto/* backup_crypto/ + +# download and patch crypto and gnxi + $(GO) mod download golang.org/x/crypto@v0.0.0-20191206172530-e9b2fee46413 + cp -r $(GOPATH)/pkg/mod/golang.org/x/crypto@v0.0.0-20191206172530-e9b2fee46413/* vendor/golang.org/x/crypto/ + chmod -R u+w vendor + patch -d vendor -p0 < patches/gnmi_cli.all.patch + patch -d vendor -p0 < patches/gnmi_set.patch + patch -d vendor -p0 < patches/gnmi_get.patch + git apply patches/0001-Updated-to-filter-and-write-to-file.patch + +ifeq ($(CROSS_BUILD_ENVIRON),y) + $(GO) build -o ${GOBIN}/gnmi_get -mod=vendor github.com/jipanyang/gnxi/gnmi_get + $(GO) build -o ${GOBIN}/gnmi_set -mod=vendor github.com/jipanyang/gnxi/gnmi_set + $(GO) build -o ${GOBIN}/gnmi_cli -mod=vendor github.com/openconfig/gnmi/cmd/gnmi_cli +else $(GO) install -mod=vendor github.com/jipanyang/gnxi/gnmi_get $(GO) install -mod=vendor github.com/jipanyang/gnxi/gnmi_set $(GO) install -mod=vendor github.com/openconfig/gnmi/cmd/gnmi_cli - $(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnoi_client - $(GO) install -mod=vendor github.com/sonic-net/sonic-gnmi/gnmi_dump endif +# restore old version + rm -rf vendor/golang.org/x/crypto/ + mv backup_crypto/ vendor/golang.org/x/crypto/ + swsscommon_wrap: make -C swsscommon diff --git a/go.mod b/go.mod index 2f783515..1607686a 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/go-redis/redis v6.15.6+incompatible github.com/godbus/dbus/v5 v5.1.0 github.com/gogo/protobuf v1.3.2 - github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/golang/protobuf v1.5.0 + github.com/golang/glog v1.2.0 + github.com/golang/protobuf v1.5.4 github.com/google/gnxi v0.0.0-20191016182648-6697a080bc2d github.com/jipanyang/gnmi v0.0.0-20180820232453-cb4d464fa018 github.com/jipanyang/gnxi v0.0.0-20181221084354-f0a90cca6fd0 @@ -22,10 +22,11 @@ require ( github.com/openconfig/gnmi v0.0.0-20200617225440-d2b4e6a45802 github.com/openconfig/gnoi v0.0.0-20211029052138-349b3dcd04ec github.com/openconfig/ygot v0.7.1 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20201110031124-69a78807bb2b - google.golang.org/grpc v1.33.2 - google.golang.org/protobuf v1.26.0 + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 + google.golang.org/grpc v1.64.1 + google.golang.org/grpc/security/advancedtls v1.0.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v2 v2.2.8 ) @@ -37,7 +38,7 @@ require ( github.com/cenkalti/backoff/v4 v4.0.0 // indirect github.com/go-redis/redis/v7 v7.0.0-beta.3.0.20190824101152-d19aba07b476 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/maruel/natural v1.1.1 // indirect github.com/onsi/ginkgo v1.10.3 // indirect github.com/onsi/gomega v1.7.1 // indirect @@ -46,10 +47,13 @@ require ( github.com/stretchr/testify v1.9.0 // indirect go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect - golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect - golang.org/x/text v0.3.3 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.16.0 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect ) -replace github.com/Azure/sonic-mgmt-common => ../sonic-mgmt-common +replace ( + github.com/Azure/sonic-mgmt-common => ../sonic-mgmt-common + golang.org/x/crypto => golang.org/x/crypto v0.24.0 +) diff --git a/go.sum b/go.sum index 7946b4e3..38b55147 100644 --- a/go.sum +++ b/go.sum @@ -18,14 +18,9 @@ github.com/c9s/goprocinfo v0.0.0-20191125144613-4acdd056c72d/go.mod h1:uEyr4WpAH github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU= github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.1-0.20210802184156-9742bd7fca1c+incompatible h1:kFnl8B5YgOXou7f+dsklKcGSXph/nubNx7I6d6RoFuE= github.com/dgrijalva/jwt-go v3.2.1-0.20210802184156-9742bd7fca1c+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= @@ -33,7 +28,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be8FqJQRhdQZ5Sg= @@ -44,8 +38,9 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -60,8 +55,9 @@ github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9c github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnxi v0.0.0-20191016182648-6697a080bc2d h1:OtErLAncPdsEEhOI4ueR48dr6uThRIPkwWcOAdQ4LyI= github.com/google/gnxi v0.0.0-20191016182648-6697a080bc2d/go.mod h1:6kkMbKS62iZMyk1q0zukcqkEJwnIhcbgg/hmoFmRDZk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -69,15 +65,14 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/jipanyang/gnmi v0.0.0-20180820232453-cb4d464fa018 h1:M++7b2XCTGqQwqu+AB0B3XzXiV+vVawnXJ4tvxUMrTU= github.com/jipanyang/gnmi v0.0.0-20180820232453-cb4d464fa018/go.mod h1:+aiusdWGFuKzi7B8/Y75kTlIA3UDF+sUBfY5+1e2NLs= github.com/jipanyang/gnxi v0.0.0-20181221084354-f0a90cca6fd0 h1:Dr/hrfbZxVlT/VvLfv8glHZAf9dLfuTSCJQq7cRGydo= @@ -111,70 +106,96 @@ github.com/openconfig/ygot v0.7.1 h1:kqDRYQpowXTr7EhGwr2BBDKJzqs+H8aFYjffYQ8lBsw github.com/openconfig/ygot v0.7.1/go.mod h1:5MwNX6DMP1QMf2eQjW+aJN/KNslVqRJtbfSL3SO6Urk= github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f h1:WyCn68lTiytVSkk7W1K9nBiSGTSRlUOdyTnSjwrIlok= github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4= -github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -185,10 +206,13 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -203,8 +227,12 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc/examples v0.0.0-20201112215255-90f1b3ee835b h1:NuxyvVZoDfHZwYW9LD4GJiF5/nhiSyP4/InTrvw9Ibk= +google.golang.org/grpc/security/advancedtls v1.0.0 h1:/KQ7VP/1bs53/aopk9QhuPyFAp9Dm9Ejix3lzYkCrDA= +google.golang.org/grpc/security/advancedtls v1.0.0/go.mod h1:o+s4go+e1PJ2AjuQMY5hU82W7lDlefjJA6FqEHRVHWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -215,8 +243,9 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -227,9 +256,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a h1:1XCVEdxrvL6c0TGOhecLuB7U9zYNdxZEjvOqJreKZiM= diff --git a/patches/0002-Fix-advance-tls-build-with-go-119.patch b/patches/0002-Fix-advance-tls-build-with-go-119.patch new file mode 100644 index 00000000..4f2dd481 --- /dev/null +++ b/patches/0002-Fix-advance-tls-build-with-go-119.patch @@ -0,0 +1,33 @@ +--- ./google.golang.org/grpc/security/advancedtls/advancedtls.go ++++ ./google.golang.org/grpc/security/advancedtls/advancedtls.go +@@ -576,7 +576,7 @@ func buildVerifyFunc(c *advancedTLSCreds, + if verifiedChains == nil { + verifiedChains = CertificateChains{rawCertList} + } +- if err := checkChainRevocation(verifiedChains, *c.revocationOptions); err != nil { ++ if err := CheckChainRevocation(verifiedChains, *c.revocationOptions); err != nil { + return err + } + } + +--- ./google.golang.org/grpc/security/advancedtls/crl.go ++++ ./google.golang.org/grpc/security/advancedtls/crl.go +@@ -119,7 +119,7 @@ var ( + + // checkChainRevocation checks the verified certificate chain + // for revoked certificates based on RFC5280. +-func checkChainRevocation(verifiedChains [][]*x509.Certificate, cfg RevocationOptions) error { ++func CheckChainRevocation(verifiedChains [][]*x509.Certificate, cfg RevocationOptions) error { + // Iterate the verified chains looking for one that is RevocationUnrevoked. + // A single RevocationUnrevoked chain is enough to allow the connection, and a single RevocationRevoked + // chain does not mean the connection should fail. +@@ -224,7 +224,7 @@ func checkCertRevocation(c *x509.Certificate, crl *CRL) (revocationStatus, error + rawEntryIssuer := crl.rawIssuer + + // Loop through all the revoked certificates. +- for _, revCert := range crl.certList.RevokedCertificateEntries { ++ for _, revCert := range crl.certList.RevokedCertificates { + // 5.3 Loop through CRL entry extensions for needed information. + for _, ext := range revCert.Extensions { + if oidCertificateIssuer.Equal(ext.Id) { +-- From e6bc0e72083eb88a6fac83ab02da2e4f2189d3c9 Mon Sep 17 00:00:00 2001 From: Hua Liu <58683130+liuh-80@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:01:53 +0800 Subject: [PATCH 10/11] Add cert CRL support. (#269) Add cert CRL support. #### Why I did it Support certificate revocation list. #### How I did it Download CRL and verify cert with CRL. #### How to verify it Manually test: I1119 06:45:56.678454 139 server.go:201] Created Server on localhost:50052, read-only: true I1119 06:45:56.678478 139 telemetry.go:465] Auth Modes: cert I1119 06:45:56.678495 139 telemetry.go:466] Starting RPC server on address: localhost:50052 I1119 06:45:56.678532 139 telemetry.go:469] GNMI Server started serving I1119 06:46:14.936024 139 clientCertAuth.go:183] Get Crl Urls for cert: [] I1119 06:46:14.936363 139 clientCertAuth.go:224] Cert does not contains and CRL distribution points I1119 06:46:14.936375 139 server.go:278] authenticate user , roles [role1] I1119 06:46:21.524943 139 clientCertAuth.go:183] Get Crl Urls for cert: [http://10.250.0.102:1234/crl] I1119 06:46:21.526022 139 clientCertAuth.go:93] SearchCrlCache not found cache for url: http://10.250.0.102:1234/crl I1119 06:46:21.526138 139 clientCertAuth.go:158] Download CRL start: http://10.250.0.102:1234/crl I1119 06:46:21.533821 139 clientCertAuth.go:176] Download CRL: http://10.250.0.102:1234/crl successed I1119 06:46:21.534318 139 clientCertAuth.go:66] CrlExpired expireTime: Wed Nov 20 06:46:21 2024, now: Tue Nov 19 06:46:21 2024 I1119 06:46:21.534337 139 clientCertAuth.go:211] CreateStaticCRLProvider add crl: http://10.250.0.102:1234/crl content: [...] I1119 06:46:21.535269 139 clientCertAuth.go:244] VerifyCertCrl peer certificate revoked: no unrevoked chains found: map[2:1] I1119 06:46:21.535289 139 clientCertAuth.go:149] [TELEMETRY-2] Failed to verify cert with CRL; rpc error: code = Unauthenticated desc = Peer certificate revoked Add new UT. #### Work item tracking Microsoft ADO (number only): 27146924 #### Which release branch to backport (provide reason below if selected) - [ ] 201811 - [ ] 201911 - [ ] 202006 - [ ] 202012 - [ ] 202106 - [ ] 202111 #### Description for the changelog Add cert CRL support. #### Link to config_db schema for YANG module changes #### A picture of a cute animal (not mandatory but encouraged) --- Makefile | 2 +- gnmi_server/clientCertAuth.go | 204 ++++++++++++++++++++++++++- gnmi_server/crl_test.go | 251 ++++++++++++++++++++++++++++++++++ gnmi_server/server.go | 3 +- gnmi_server/server_test.go | 10 +- telemetry/telemetry.go | 7 + testdata/crl/revokedInt.pem | 58 ++++++++ testdata/crl/test.crl | 11 ++ testdata/crl/unrevoked.pem | 58 ++++++++ 9 files changed, 596 insertions(+), 8 deletions(-) create mode 100644 gnmi_server/crl_test.go create mode 100644 testdata/crl/revokedInt.pem create mode 100644 testdata/crl/test.crl create mode 100644 testdata/crl/unrevoked.pem diff --git a/Makefile b/Makefile index 039fed73..817d853f 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ go-deps-clean: sonic-gnmi: $(GO_DEPS) # advancetls 1.0.0 release need following patch to build by go-1.19 -# patch -d vendor -p0 < patches/0002-Fix-advance-tls-build-with-go-119.patch + patch -d vendor -p0 < patches/0002-Fix-advance-tls-build-with-go-119.patch # build service first which depends on advancetls ifeq ($(CROSS_BUILD_ENVIRON),y) $(GO) build -o ${GOBIN}/telemetry -mod=vendor $(BLD_FLAGS) github.com/sonic-net/sonic-gnmi/telemetry diff --git a/gnmi_server/clientCertAuth.go b/gnmi_server/clientCertAuth.go index 9a4a9a4f..48fecf3c 100644 --- a/gnmi_server/clientCertAuth.go +++ b/gnmi_server/clientCertAuth.go @@ -1,6 +1,11 @@ package gnmi import ( + "crypto/tls" + "crypto/x509" + "io" + "net/http" + "time" "github.com/sonic-net/sonic-gnmi/common_utils" "github.com/sonic-net/sonic-gnmi/swsscommon" "github.com/golang/glog" @@ -9,9 +14,103 @@ import ( "google.golang.org/grpc/credentials" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" + "google.golang.org/grpc/security/advancedtls" ) -func ClientCertAuthenAndAuthor(ctx context.Context, serviceConfigTableName string) (context.Context, error) { +const DEFAULT_CRL_EXPIRE_DURATION time.Duration = 24 * 60* 60 * time.Second + +type Crl struct { + thisUpdate time.Time + nextUpdate time.Time + crl []byte +} + +// CRL content cache +var CrlCache map[string]*Crl = nil + +// CRL content cache +var CrlDxpireDuration time.Duration = DEFAULT_CRL_EXPIRE_DURATION + +func InitCrlCache() { + if CrlCache == nil { + CrlCache = make(map[string]*Crl) + } +} + +func ReleaseCrlCache() { + for mapkey, _ := range(CrlCache) { + delete(CrlCache, mapkey) + } +} + +func AppendCrlToCache(url string, rawCRL []byte) { + crl := new(Crl) + crl.thisUpdate = time.Now() + crl.nextUpdate = time.Now() + crl.crl = rawCRL + + CrlCache[url] = crl +} + +func GetCrlExpireDuration() time.Duration { + return CrlDxpireDuration +} + +func SetCrlExpireDuration(duration time.Duration) { + CrlDxpireDuration = duration +} + +func CrlExpired(crl *Crl) bool { + now := time.Now() + expireTime := crl.thisUpdate.Add(GetCrlExpireDuration()) + glog.Infof("CrlExpired expireTime: %s, now: %s", expireTime.Format(time.ANSIC), now.Format(time.ANSIC)) + // CRL expiresion policy follow the policy of Get-CRLFreshness command in following doc: + // https://learn.microsoft.com/en-us/archive/blogs/russellt/get-crlfreshness + // The policy are: + // 1. CRL expired when current time is after CRL expiresion time, which defined in "Next CRL Publish" extension. + // Because CRL cached in memory, GNMI support OnDemand CRL referesh by restart GNMI service. + return now.After(expireTime) +} + +func CrlNeedUpdate(crl *Crl) bool { + now := time.Now() + glog.Infof("CrlNeedUpdate nextUpdate: %s, now: %s", crl.nextUpdate.Format(time.ANSIC), now.Format(time.ANSIC)) + return now.After(crl.nextUpdate) +} + +func RemoveExpiredCrl() { + for mapkey, crl := range(CrlCache) { + if CrlExpired(crl) { + glog.Infof("RemoveExpiredCrl key: %s", mapkey) + delete(CrlCache, mapkey) + } + } +} + +func SearchCrlCache(url string) (bool, *Crl) { + crl, exist := CrlCache[url] + if !exist { + glog.Infof("SearchCrlCache not found cache for url: %s", url) + return false, nil + } + + if CrlExpired(crl) { + glog.Infof("SearchCrlCache crl expired: %s", url) + delete(CrlCache, url) + return false, nil + } + + if CrlNeedUpdate(crl) { + glog.Infof("SearchCrlCache crl need update: %s", url) + delete(CrlCache, url) + return false, nil + } + + glog.Infof("SearchCrlCache found cache for url: %s", url) + return true, crl +} + +func ClientCertAuthenAndAuthor(ctx context.Context, serviceConfigTableName string, enableCrl bool) (context.Context, error) { rc, ctx := common_utils.GetContext(ctx) p, ok := peer.FromContext(ctx) if !ok { @@ -44,9 +143,112 @@ func ClientCertAuthenAndAuthor(ctx context.Context, serviceConfigTableName strin } } + if enableCrl { + err := VerifyCertCrl(tlsAuth.State) + if err != nil { + glog.Infof("[%s] Failed to verify cert with CRL; %v", rc.ID, err) + return ctx, err + } + } + return ctx, nil } +func TryDownload(url string) bool { + glog.Infof("Download CRL start: %s", url) + resp, err := http.Get(url) + + if resp != nil { + defer resp.Body.Close() + } + + if err != nil || resp.StatusCode != http.StatusOK { + glog.Infof("Download CRL: %s failed: %v", url, err) + return false + } + + crlContent, err := io.ReadAll(resp.Body) + if err != nil { + glog.Infof("Download CRL: %s failed: %v", url, err) + return false + } + + glog.Infof("Download CRL: %s successed", url) + AppendCrlToCache(url, crlContent) + + return true +} + +func GetCrlUrls(cert x509.Certificate) []string { + glog.Infof("Get Crl Urls for cert: %v", cert.CRLDistributionPoints) + return cert.CRLDistributionPoints +} + +func DownloadNotCachedCrl(crlUrlArray []string) bool { + crlAvaliable := false + for _, crlUrl := range crlUrlArray{ + exist, _ := SearchCrlCache(crlUrl) + if exist { + crlAvaliable = true + } else { + downloaded := TryDownload(crlUrl) + if downloaded { + crlAvaliable = true + } + } + } + + return crlAvaliable +} + +func CreateStaticCRLProvider() *advancedtls.StaticCRLProvider { + crlArray := make([][]byte, 1) + for mapkey, item := range(CrlCache) { + if CrlExpired(item) { + glog.Infof("CreateStaticCRLProvider remove expired crl: %s", mapkey) + delete(CrlCache, mapkey) + } else { + glog.Infof("CreateStaticCRLProvider add crl: %s content: %v", mapkey, item.crl) + crlArray = append(crlArray, item.crl) + } + } + + return advancedtls.NewStaticCRLProvider(crlArray) +} + +func VerifyCertCrl(tlsConnState tls.ConnectionState) error { + InitCrlCache() + // Check if any CRL already exist in local + crlUriArray := GetCrlUrls(*tlsConnState.VerifiedChains[0][0]) + if len(crlUriArray) == 0 { + glog.Infof("Cert does not contains and CRL distribution points") + return nil + } + + crlAvaliable := DownloadNotCachedCrl(crlUriArray) + if !crlAvaliable { + // Every certificate will contain multiple CRL distribution points. + // If all CRLs are not available, the certificate validation should be blocked. + glog.Infof("VerifyCertCrl can't download CRL and verify cert: %v", crlUriArray) + return status.Errorf(codes.Unauthenticated, "Can't download CRL and verify cert") + } + + // Build CRL provider from cache and verify cert + crlProvider := CreateStaticCRLProvider() + err := advancedtls.CheckChainRevocation(tlsConnState.VerifiedChains, advancedtls.RevocationOptions{ + DenyUndetermined: false, + CRLProvider: crlProvider, + }) + + if err != nil { + glog.Infof("VerifyCertCrl peer certificate revoked: %v", err.Error()) + return status.Error(codes.Unauthenticated, "Peer certificate revoked") + } + + glog.Infof("VerifyCertCrl verify cert passed: %v", crlUriArray) + return nil +} + func PopulateAuthStructByCommonName(certCommonName string, auth *common_utils.AuthInfo, serviceConfigTableName string) error { if serviceConfigTableName == "" { return status.Errorf(codes.Unauthenticated, "Service config table name should not be empty") diff --git a/gnmi_server/crl_test.go b/gnmi_server/crl_test.go new file mode 100644 index 00000000..c4c53b19 --- /dev/null +++ b/gnmi_server/crl_test.go @@ -0,0 +1,251 @@ +package gnmi + +// server_test covers gNMI get, subscribe (stream and poll) test +// Prerequisite: redis-server should be running. +import ( + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "os" + "testing" + "time" + "github.com/agiledragon/gomonkey/v2" + "github.com/sonic-net/sonic-gnmi/common_utils" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestCrlExpireDuration(t *testing.T) { + duration := GetCrlExpireDuration() + if duration != DEFAULT_CRL_EXPIRE_DURATION { + t.Errorf("TestCrlExpireDuration test failed, default expire duration incorrect.") + } + + newDuration := 60 * time.Second + SetCrlExpireDuration(newDuration) + duration = GetCrlExpireDuration() + if duration != newDuration { + t.Errorf("TestCrlExpireDuration test failed, change expire duration failed.") + } +} + +func TestCrlCache(t *testing.T) { + InitCrlCache() + defer ReleaseCrlCache() + + rawCRL, _ := os.ReadFile("../testdata/crl/test.crl") + if rawCRL == nil { + t.Errorf("TestCrlCache test failed, crl file missing.") + } + AppendCrlToCache("http://test.crl.com/test.crl", rawCRL) + + // mock to make test CRL valied + mockCrlExpired := gomonkey.ApplyFunc(CrlExpired, func(crl *Crl) bool { + return true + }) + + // test CRL expired + exist, cacheItem := SearchCrlCache("http://test.crl.com/test.crl") + if exist { + t.Errorf("TestCrlCache test failed, crl should expired.") + } + + if cacheItem != nil { + t.Errorf("TestCrlCache test failed, crl content incorrect.") + } + + // test CRL expired and remove + AppendCrlToCache("http://test.crl.com/test.crl", rawCRL) + RemoveExpiredCrl() + _, exist = CrlCache["http://test.crl.com/test.crl"] + if exist { + t.Errorf("TestCrlCache test failed, expired crl should removed.") + } + + // test CRL does not exist + exist, cacheItem = SearchCrlCache("http://test.crl.com/notexist.crl") + if exist { + t.Errorf("TestCrlCache test failed, crl should not exist.") + } + + if cacheItem != nil { + t.Errorf("TestCrlCache test failed, crl content incorrect.") + } + + // mock to make test CRL valied + mockCrlExpired.Reset() + mockCrlNeedUpdate := gomonkey.ApplyFunc(CrlNeedUpdate, func(crl *Crl) bool { + return false + }) + defer mockCrlNeedUpdate.Reset() + + AppendCrlToCache("http://test.crl.com/test.crl", rawCRL) + exist, cacheItem = SearchCrlCache("http://test.crl.com/test.crl") + if !exist { + t.Errorf("TestCrlCache test failed, crl should exist.") + } + + if len(cacheItem.crl) != len(rawCRL) { + t.Errorf("TestCrlCache test failed, crl content incorrect.") + } +} + +func TestGetCrlUrls(t *testing.T) { + cert := x509.Certificate{ + Subject: pkix.Name{ + CommonName: "certname1", + }, + CRLDistributionPoints: []string{ + "http://test.crl.com/test.crl", + }, + } + + crlUrlArray := GetCrlUrls(cert) + + if len(crlUrlArray) != 1 { + t.Errorf("TestGetCrlUrls get incorrect CRLDistributionPoints.") + } + + if crlUrlArray[0] != "http://test.crl.com/test.crl" { + t.Errorf("TestGetCrlUrls get incorrect CRL.") + } +} + +func makeChain(name string) []*x509.Certificate { + certChain := make([]*x509.Certificate, 0) + + rest, err := os.ReadFile(name) + if err != nil { + fmt.Printf("makeChain ReadFile err: %s\n", err.Error()) + } + + for len(rest) > 0 { + var block *pem.Block + block, rest = pem.Decode(rest) + c, err := x509.ParseCertificate(block.Bytes) + if err != nil { + fmt.Printf("makeChain ParseCertificate err: %s\n", err.Error()) + } + certChain = append(certChain, c) + } + return certChain +} + +func CreateConnectionState(certPath string) tls.ConnectionState { + certChain := makeChain(certPath) + return tls.ConnectionState { + VerifiedChains: [][]*x509.Certificate { + certChain, + }, + } +} + +func TestVerifyCertCrl(t *testing.T) { + InitCrlCache() + defer ReleaseCrlCache() + + mockGetCrlUrls := gomonkey.ApplyFunc(GetCrlUrls, func(cert x509.Certificate) []string { + return []string{ "http://test.crl.com/test.crl" } + }) + defer mockGetCrlUrls.Reset() + + mockCrlExpired := gomonkey.ApplyFunc(CrlExpired, func(crl *Crl) bool { + return false + }) + defer mockCrlExpired.Reset() + + mockTryDownload := gomonkey.ApplyFunc(TryDownload, func(url string) bool { + rawCRL, _ := os.ReadFile("../testdata/crl/test.crl") + AppendCrlToCache("http://test.crl.com/test.crl", rawCRL) + return true + }) + defer mockTryDownload.Reset() + + // test revoked cert + tlsConnState := CreateConnectionState("../testdata/crl/revokedInt.pem") + err := VerifyCertCrl(tlsConnState) + if err == nil { + t.Errorf("TestVerifyCertCrl verify revoked cert failed.") + } + + // test valid cert + tlsConnState = CreateConnectionState("../testdata/crl/unrevoked.pem") + err = VerifyCertCrl(tlsConnState) + if err != nil { + t.Errorf("TestVerifyCertCrl verify unrevoked cert failed.") + } +} + + +func TestVerifyCertCrlWithDownloadFailed(t *testing.T) { + InitCrlCache() + defer ReleaseCrlCache() + + mockGetCrlUrls := gomonkey.ApplyFunc(GetCrlUrls, func(cert x509.Certificate) []string { + return []string{ "http://test.crl.com/test.crl" } + }) + defer mockGetCrlUrls.Reset() + + mockTryDownload := gomonkey.ApplyFunc(TryDownload, func(url string) bool { + return false + }) + defer mockTryDownload.Reset() + + // test valid cert,should failed because download CRL failed + tlsConnState := CreateConnectionState("../testdata/crl/unrevoked.pem") + err := VerifyCertCrl(tlsConnState) + if err == nil { + t.Errorf("TestVerifyCertCrl verify unrevoked cert should failed when CRL can't download.") + } +} + +func TestClientCertAuthenAndAuthorWithCrl(t *testing.T) { + // initialize err variable + err := status.Error(codes.Unauthenticated, "") + + // when config table is empty, will authorize with PopulateAuthStruct + mockpopulate := gomonkey.ApplyFunc(PopulateAuthStruct, func(username string, auth *common_utils.AuthInfo, r []string) error { + return nil + }) + defer mockpopulate.Reset() + + // mock for revoked cert + mockVerifyCertCrl := gomonkey.ApplyFunc(VerifyCertCrl, func(tlsConnState tls.ConnectionState) error { + return status.Error(codes.Unauthenticated, "Peer certificate revoked") + }) + + // check auth with nil cert name + ctx, cancel := CreateAuthorizationCtx() + ctx, err = ClientCertAuthenAndAuthor(ctx, "", true) + if err == nil { + t.Errorf("Auth with revoked cert should failed.") + } + + cancel() + mockVerifyCertCrl.Reset() + + // mock for unrevoked cert + mockVerifyCertCrl = gomonkey.ApplyFunc(VerifyCertCrl, func(tlsConnState tls.ConnectionState) error { + return nil + }) + + // check auth with nil cert name + ctx, cancel = CreateAuthorizationCtx() + ctx, err = ClientCertAuthenAndAuthor(ctx, "", true) + if err != nil { + t.Errorf("Auth with revoked cert should failed: %v", err) + } + + cancel() + mockVerifyCertCrl.Reset() +} + +func TestTryDownload(t *testing.T) { + // Use this test case for improve coverage + downloaded := TryDownload("http://127.0.0.1:1234/") + if downloaded != false { + t.Errorf("Download should failed: %v", downloaded) + } +} \ No newline at end of file diff --git a/gnmi_server/server.go b/gnmi_server/server.go index f3ec24ce..23dd817c 100644 --- a/gnmi_server/server.go +++ b/gnmi_server/server.go @@ -86,6 +86,7 @@ type Config struct { IdleConnDuration int ConfigTableName string Vrf string + EnableCrl bool } var AuthLock sync.Mutex @@ -263,7 +264,7 @@ func authenticate(config *Config, ctx context.Context) (context.Context, error) } } if !success && config.UserAuth.Enabled("cert") { - ctx, err = ClientCertAuthenAndAuthor(ctx, config.ConfigTableName) + ctx, err = ClientCertAuthenAndAuthor(ctx, config.ConfigTableName, config.EnableCrl) if err == nil { success = true } diff --git a/gnmi_server/server_test.go b/gnmi_server/server_test.go index b97e2f63..40a90abc 100644 --- a/gnmi_server/server_test.go +++ b/gnmi_server/server_test.go @@ -4490,7 +4490,7 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { return ctx, cancel } - func TestClientCertAuthenAndAuthor(t *testing.T) { +func TestClientCertAuthenAndAuthor(t *testing.T) { if !swsscommon.SonicDBConfigIsInit() { swsscommon.SonicDBConfigInitialize() } @@ -4510,7 +4510,7 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { // check auth with nil cert name ctx, cancel := CreateAuthorizationCtx() - ctx, err = ClientCertAuthenAndAuthor(ctx, "") + ctx, err = ClientCertAuthenAndAuthor(ctx, "", false) if err != nil { t.Errorf("CommonNameMatch with empty config table should success: %v", err) } @@ -4521,7 +4521,7 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { ctx, cancel = CreateAuthorizationCtx() configDb.Flushdb() gnmiTable.Hset("certname1", "role", "role1") - ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT", false) if err != nil { t.Errorf("CommonNameMatch with correct cert name should success: %v", err) } @@ -4533,7 +4533,7 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { configDb.Flushdb() gnmiTable.Hset("certname1", "role", "role1") gnmiTable.Hset("certname2", "role", "role2") - ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT", false) if err != nil { t.Errorf("CommonNameMatch with correct cert name should success: %v", err) } @@ -4544,7 +4544,7 @@ func CreateAuthorizationCtx() (context.Context, context.CancelFunc) { ctx, cancel = CreateAuthorizationCtx() configDb.Flushdb() gnmiTable.Hset("certname2", "role", "role2") - ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT") + ctx, err = ClientCertAuthenAndAuthor(ctx, "GNMI_CLIENT_CERT", false) if err == nil { t.Errorf("CommonNameMatch with invalid cert name should fail: %v", err) } diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index cb56e10c..f310a4d7 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -58,6 +58,8 @@ type TelemetryConfig struct { WithSaveOnSet *bool IdleConnDuration *int Vrf *string + EnableCrl *bool + CrlExpireDuration *int } func main() { @@ -167,6 +169,8 @@ func setupFlags(fs *flag.FlagSet) (*TelemetryConfig, *gnmi.Config, error) { WithSaveOnSet: fs.Bool("with-save-on-set", false, "Enables save-on-set."), IdleConnDuration: fs.Int("idle_conn_duration", 5, "Seconds before server closes idle connections"), Vrf: fs.String("vrf", "", "VRF name, when zmq_address belong on a VRF, need VRF name to bind ZMQ."), + EnableCrl: fs.Bool("enable_crl", false, "Enable certificate revocation list"), + CrlExpireDuration: fs.Int("crl_expire_duration", 86400, "Certificate revocation list cache expire duration"), } fs.Var(&telemetryCfg.UserAuth, "client_auth", "Client auth mode(s) - none,cert,password") @@ -230,6 +234,9 @@ func setupFlags(fs *flag.FlagSet) (*TelemetryConfig, *gnmi.Config, error) { cfg.IdleConnDuration = int(*telemetryCfg.IdleConnDuration) cfg.ConfigTableName = *telemetryCfg.ConfigTableName cfg.Vrf = *telemetryCfg.Vrf + cfg.EnableCrl = *telemetryCfg.EnableCrl + + gnmi.SetCrlExpireDuration(time.Duration(*telemetryCfg.CrlExpireDuration) * time.Second) // TODO: After other dependent projects are migrated to ZmqPort, remove ZmqAddress zmqAddress := *telemetryCfg.ZmqAddress diff --git a/testdata/crl/revokedInt.pem b/testdata/crl/revokedInt.pem new file mode 100644 index 00000000..8b7282ff --- /dev/null +++ b/testdata/crl/revokedInt.pem @@ -0,0 +1,58 @@ +-----BEGIN CERTIFICATE----- +MIIDAzCCAqmgAwIBAgITAWjKwm2dNQvkO62Jgyr5rAvVQzAKBggqhkjOPQQDAjCB +pTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v +dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBMTEMxJjARBgNVBAsTClByb2R1 +Y3Rpb24wEQYDVQQLEwpjYW1wdXMtc2xuMSwwKgYDVQQDEyNSb290IENBICgyMDIx +LTAyLTAyVDA3OjMxOjU0LTA4OjAwKTAgFw0yMTAyMDIxNTMxNTRaGA85OTk5MTIz +MTIzNTk1OVowgaUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw +FAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMSYwEQYD +VQQLEwpQcm9kdWN0aW9uMBEGA1UECxMKY2FtcHVzLXNsbjEsMCoGA1UEAxMjUm9v +dCBDQSAoMjAyMS0wMi0wMlQwNzozMTo1NC0wODowMCkwWTATBgcqhkjOPQIBBggq +hkjOPQMBBwNCAAQhA0/puhTtSxbVVHseVhL2z7QhpPyJs5Q4beKi7tpaYRDmVn6p +Phh+jbRzg8Qj4gKI/Q1rrdm4rKer63LHpdWdo4GzMIGwMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUeq/TQ959KbWk/um08jSTXogXpWUwHwYDVR0jBBgwFoAUeq/T +Q959KbWk/um08jSTXogXpWUwLgYDVR0RBCcwJYYjc3BpZmZlOi8vY2FtcHVzLXNs +bi5wcm9kLmdvb2dsZS5jb20wCgYIKoZIzj0EAwIDSAAwRQIgOSQZvyDPQwVOWnpF +zWvI+DS2yXIj/2T2EOvJz2XgcK4CIQCL0mh/+DxLiO4zzbInKr0mxpGSxSeZCUk7 +1ZF7AeLlbw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDizCCAzKgAwIBAgIUAK6BGFvOeQUak65aL+XAQhr5LrcwCgYIKoZIzj0EAwIw +gaUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N +b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMSYwEQYDVQQLEwpQcm9k +dWN0aW9uMBEGA1UECxMKY2FtcHVzLXNsbjEsMCoGA1UEAxMjUm9vdCBDQSAoMjAy +MS0wMi0wMlQwNzozMTo1NC0wODowMCkwIBcNMjEwMjAyMTUzMTU0WhgPOTk5OTEy +MzEyMzU5NTlaMIGlMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UEChMKR29vZ2xlIExMQzEmMBEG +A1UECxMKUHJvZHVjdGlvbjARBgNVBAsTCmNhbXB1cy1zbG4xLDAqBgNVBAMTI25v +ZGUgQ0EgKDIwMjEtMDItMDJUMDc6MzE6NTQtMDg6MDApMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEye6UOlBos8Q3FFBiLahD9BaLTA18bO4MTPyv35T3lppvxD5X +U/AnEllOnx5OMtMjMBbIQjSkMbiQ9xNXoSqB6aOCATowggE2MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUhWfy0gWBmkh2GiaBgnZzlQsvOlIwHwYDVR0jBBgwFoAU +eq/TQ959KbWk/um08jSTXogXpWUwMwYDVR0RBCwwKoYoc3BpZmZlOi8vbm9kZS5j +YW1wdXMtc2xuLnByb2QuZ29vZ2xlLmNvbTA7BgNVHR4BAf8EMTAvoC0wK4YpY3Nj +cy10ZWFtLm5vZGUuY2FtcHVzLXNsbi5wcm9kLmdvb2dsZS5jb20wQgYDVR0fBDsw +OTA3oDWgM4YxaHR0cDovL3N0YXRpYy5jb3JwLmdvb2dsZS5jb20vY3JsL2NhbXB1 +cy1zbG4vbm9kZTAKBggqhkjOPQQDAgNHADBEAiA79rPu6ZO1/0qB6RxL7jVz1200 +UTo8ioB4itbTzMnJqAIgJqp/Rc8OhpsfzQX8XnIIkl+SewT+tOxJT1MHVNMlVhc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC0DCCAnWgAwIBAgITXQ2c/C27OGqk4Pbu+MNJlOtpYTAKBggqhkjOPQQDAjCB +pTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v +dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBMTEMxJjARBgNVBAsTClByb2R1 +Y3Rpb24wEQYDVQQLEwpjYW1wdXMtc2xuMSwwKgYDVQQDEyNub2RlIENBICgyMDIx +LTAyLTAyVDA3OjMxOjU0LTA4OjAwKTAgFw0yMTAyMDIxNTMxNTRaGA85OTk5MTIz +MTIzNTk1OVowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABN2/1le5d3hS/piw +hrNMHjd7gPEjzXwtuXQTzdV+aaeOf3ldnC6OnEF/bggym9MldQSJZLXPYSaoj430 +Vu5PRNejggEkMIIBIDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH +AwIGCCsGAQUFBwMBMB0GA1UdDgQWBBTEewP3JgrJPekWWGGjChVqaMhaqTAfBgNV +HSMEGDAWgBSFZ/LSBYGaSHYaJoGCdnOVCy86UjBrBgNVHREBAf8EYTBfghZqemFi +MTIucHJvZC5nb29nbGUuY29thkVzcGlmZmU6Ly9jc2NzLXRlYW0ubm9kZS5jYW1w +dXMtc2xuLnByb2QuZ29vZ2xlLmNvbS9yb2xlL2JvcmctYWRtaW4tY28wQgYDVR0f +BDswOTA3oDWgM4YxaHR0cDovL3N0YXRpYy5jb3JwLmdvb2dsZS5jb20vY3JsL2Nh +bXB1cy1zbG4vbm9kZTAKBggqhkjOPQQDAgNJADBGAiEA9w4qp3nHpXo+6d7mZc69 +QoALfP5ynfBCArt8bAlToo8CIQCgc/lTfl2BtBko+7h/w6pKxLeuoQkvCL5gHFyK +LXE6vA== +-----END CERTIFICATE----- diff --git a/testdata/crl/test.crl b/testdata/crl/test.crl new file mode 100644 index 00000000..d37ad224 --- /dev/null +++ b/testdata/crl/test.crl @@ -0,0 +1,11 @@ +-----BEGIN X509 CRL----- +MIIBiDCCAS8CAQEwCgYIKoZIzj0EAwIwgaUxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +EwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpH +b29nbGUgTExDMSYwEQYDVQQLEwpQcm9kdWN0aW9uMBEGA1UECxMKY2FtcHVzLXNs +bjEsMCoGA1UEAxMjUm9vdCBDQSAoMjAyMS0wMi0wMlQwNzozMTo1NC0wODowMCkX +DTIxMDIwMjE1MzE1NFoXDTIxMDIwOTE1MzE1NFowJzAlAhQAroEYW855BRqTrlov +5cBCGvkutxcNMjEwMjAyMTUzMTU0WqAvMC0wHwYDVR0jBBgwFoAUeq/TQ959KbWk +/um08jSTXogXpWUwCgYDVR0UBAMCAQEwCgYIKoZIzj0EAwIDRwAwRAIgaSOIhJDg +wOLYlbXkmxW0cqy/AfOUNYbz5D/8/FfvhosCICftg7Vzlu0Nh83jikyjy+wtkiJt +ZYNvGFQ3Sp2L3A9e +-----END X509 CRL----- diff --git a/testdata/crl/unrevoked.pem b/testdata/crl/unrevoked.pem new file mode 100644 index 00000000..5c5fc58a --- /dev/null +++ b/testdata/crl/unrevoked.pem @@ -0,0 +1,58 @@ +-----BEGIN CERTIFICATE----- +MIIDBDCCAqqgAwIBAgIUALy864QhnkTdceLH52k2XVOe8IQwCgYIKoZIzj0EAwIw +gaUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N +b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMSYwEQYDVQQLEwpQcm9k +dWN0aW9uMBEGA1UECxMKY2FtcHVzLXNsbjEsMCoGA1UEAxMjUm9vdCBDQSAoMjAy +MS0wMi0wMlQwNzozMDozNi0wODowMCkwIBcNMjEwMjAyMTUzMDM2WhgPOTk5OTEy +MzEyMzU5NTlaMIGlMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UEChMKR29vZ2xlIExMQzEmMBEG +A1UECxMKUHJvZHVjdGlvbjARBgNVBAsTCmNhbXB1cy1zbG4xLDAqBgNVBAMTI1Jv +b3QgQ0EgKDIwMjEtMDItMDJUMDc6MzA6MzYtMDg6MDApMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEYv/JS5hQ5kIgdKqYZWTKCO/6gloHAmIb1G8lmY0oXLXYNHQ4 +qHN7/pPtlcHQp0WK/hM8IGvgOUDoynA8mj0H9KOBszCBsDAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFPQNtnCIBcG4ReQgoVi0kPgTROseMB8GA1UdIwQYMBaAFPQN +tnCIBcG4ReQgoVi0kPgTROseMC4GA1UdEQQnMCWGI3NwaWZmZTovL2NhbXB1cy1z +bG4ucHJvZC5nb29nbGUuY29tMAoGCCqGSM49BAMCA0gAMEUCIQDwBn20DB4X/7Uk +Q5BR8JxQYUPxOfvuedjfeA8bPvQ2FwIgOEWa0cXJs1JxarILJeCXtdXvBgu6LEGQ +3Pk/bgz8Gek= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDizCCAzKgAwIBAgIUAM/6RKQ7Vke0i4xp5LaAqV73cmIwCgYIKoZIzj0EAwIw +gaUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N +b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMSYwEQYDVQQLEwpQcm9k +dWN0aW9uMBEGA1UECxMKY2FtcHVzLXNsbjEsMCoGA1UEAxMjUm9vdCBDQSAoMjAy +MS0wMi0wMlQwNzozMDozNi0wODowMCkwIBcNMjEwMjAyMTUzMDM2WhgPOTk5OTEy +MzEyMzU5NTlaMIGlMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UEChMKR29vZ2xlIExMQzEmMBEG +A1UECxMKUHJvZHVjdGlvbjARBgNVBAsTCmNhbXB1cy1zbG4xLDAqBgNVBAMTI25v +ZGUgQ0EgKDIwMjEtMDItMDJUMDc6MzA6MzYtMDg6MDApMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEllnhxmMYiUPUgRGmenbnm10gXpM94zHx3D1/HumPs6arjYuT +Zlhx81XL+g4bu4HII2qcGdP+Hqj/MMFNDI9z4aOCATowggE2MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUGOhXkmeT+CnWTt+ZbCS9OT9wX8gwHwYDVR0jBBgwFoAU +9A22cIgFwbhF5CChWLSQ+BNE6x4wMwYDVR0RBCwwKoYoc3BpZmZlOi8vbm9kZS5j +YW1wdXMtc2xuLnByb2QuZ29vZ2xlLmNvbTA7BgNVHR4BAf8EMTAvoC0wK4YpY3Nj +cy10ZWFtLm5vZGUuY2FtcHVzLXNsbi5wcm9kLmdvb2dsZS5jb20wQgYDVR0fBDsw +OTA3oDWgM4YxaHR0cDovL3N0YXRpYy5jb3JwLmdvb2dsZS5jb20vY3JsL2NhbXB1 +cy1zbG4vbm9kZTAKBggqhkjOPQQDAgNHADBEAiA86egqPw0qyapAeMGbHxrmYZYa +i5ARQsSKRmQixgYizQIgW+2iRWN6Kbqt4WcwpmGv/xDckdRXakF5Ign/WUDO5u4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICzzCCAnWgAwIBAgITYjjKfYZUKQNUjNyF+hLDGpHJKTAKBggqhkjOPQQDAjCB +pTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v +dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBMTEMxJjARBgNVBAsTClByb2R1 +Y3Rpb24wEQYDVQQLEwpjYW1wdXMtc2xuMSwwKgYDVQQDEyNub2RlIENBICgyMDIx +LTAyLTAyVDA3OjMwOjM2LTA4OjAwKTAgFw0yMTAyMDIxNTMwMzZaGA85OTk5MTIz +MTIzNTk1OVowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD4r4+nCgZExYF8v +CLvGn0lY/cmam8mAkJDXRN2Ja2t+JwaTOptPmbbXft+1NTk5gCg5wB+FJCnaV3I/ +HaxEhBWjggEkMIIBIDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH +AwIGCCsGAQUFBwMBMB0GA1UdDgQWBBTTCjXX1Txjc00tBg/5cFzpeCSKuDAfBgNV +HSMEGDAWgBQY6FeSZ5P4KdZO35lsJL05P3BfyDBrBgNVHREBAf8EYTBfghZqemFi +MTIucHJvZC5nb29nbGUuY29thkVzcGlmZmU6Ly9jc2NzLXRlYW0ubm9kZS5jYW1w +dXMtc2xuLnByb2QuZ29vZ2xlLmNvbS9yb2xlL2JvcmctYWRtaW4tY28wQgYDVR0f +BDswOTA3oDWgM4YxaHR0cDovL3N0YXRpYy5jb3JwLmdvb2dsZS5jb20vY3JsL2Nh +bXB1cy1zbG4vbm9kZTAKBggqhkjOPQQDAgNIADBFAiBq3URViNyMLpvzZHC1Y+4L ++35guyIJfjHu08P3S8/xswIhAJtWSQ1ZtozdOzGxg7GfUo4hR+5SP6rBTgIqXEfq +48fW +-----END CERTIFICATE----- From 2c4b9c85833b4b71b35fd1099271bd67aaa3b3b3 Mon Sep 17 00:00:00 2001 From: Hua Liu <58683130+liuh-80@users.noreply.github.com> Date: Fri, 22 Nov 2024 14:32:32 +0800 Subject: [PATCH 11/11] Add swss-common log level support to gnmi (#330) --- telemetry/telemetry.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index f310a4d7..4ebf6857 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -26,6 +26,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" + "github.com/sonic-net/sonic-gnmi/swsscommon" ) type ServerControlValue int @@ -88,6 +89,9 @@ func runTelemetry(args []string) error { return err } + // enable swss-common debug level + swsscommon.LoggerLinkToDbNative("telemetry") + var wg sync.WaitGroup // serverControlSignal channel is a channel that will be used to notify gnmi server to start, stop, restart, depending of syscall or cert updates var serverControlSignal = make(chan ServerControlValue, 1)