Skip to content

Commit

Permalink
Merge pull request sonic-net#319 from hdwhdw/upgrade
Browse files Browse the repository at this point in the history
Add DBUS dependencies for System.SetPackage
  • Loading branch information
hdwhdw authored Dec 9, 2024
2 parents 2c4b9c8 + 5d68f51 commit 6eade51
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 23 deletions.
12 changes: 8 additions & 4 deletions common_utils/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -37,6 +36,7 @@ const requestContextKey contextkey = 0
var requestCounter uint64

type CounterType int

const (
GNMI_GET CounterType = iota
GNMI_GET_FAIL
Expand All @@ -55,6 +55,8 @@ const (
DBUS_RESTART_SERVICE
DBUS_FILE_STAT
DBUS_HALT_SYSTEM
DBUS_IMAGE_DOWNLOAD
DBUS_IMAGE_INSTALL
COUNTER_SIZE
)

Expand Down Expand Up @@ -94,14 +96,17 @@ func (c CounterType) String() string {
return "DBUS file stat"
case DBUS_HALT_SYSTEM:
return "DBUS halt system"
case DBUS_IMAGE_DOWNLOAD:
return "DBUS image download"
case DBUS_IMAGE_INSTALL:
return "DBUS image install"
default:
return ""
}
}

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
Expand Down Expand Up @@ -137,4 +142,3 @@ func IncCounter(cnt CounterType) {
atomic.AddUint64(&globalCounters[cnt], 1)
SetMemCounters(&globalCounters)
}

55 changes: 39 additions & 16 deletions sonic_service_client/dbus_client.go
Original file line number Diff line number Diff line change
@@ -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"
)

Expand All @@ -14,19 +15,21 @@ 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)
HaltSystem() 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) {
Expand Down Expand Up @@ -194,19 +197,39 @@ func (c *DbusClient) GetFileStat(path string) (map[string]string, error) {
}

func (c *DbusClient) HaltSystem() error {
// Increment the counter for the DBUS_HALT_SYSTEM event
common_utils.IncCounter(common_utils.DBUS_HALT_SYSTEM)
// 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 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
//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
// Invoke the D-Bus API to execute the halt command
_, err := DbusApi(busName, busPath, intName, 10, RebootMethod_HALT)
return err
}

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
}
164 changes: 161 additions & 3 deletions sonic_service_client/dbus_client_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package host_service

import (
"testing"
"reflect"
"testing"

"github.com/agiledragon/gomonkey/v2"
"github.com/godbus/dbus/v5"
Expand All @@ -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
Expand Down Expand Up @@ -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
})
Expand Down Expand Up @@ -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)
}
}

0 comments on commit 6eade51

Please sign in to comment.