From 2846d28717a381d2ffede75479e1c8c043b942ba Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Fri, 1 Nov 2024 19:51:16 +0000 Subject: [PATCH 1/3] 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 2/3] 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 d62df54d549737722f0bc48074611b914c0d1c14 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Wed, 6 Nov 2024 22:21:45 +0000 Subject: [PATCH 3/3] 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"