Skip to content

Commit

Permalink
feat(storage/nvme): add get backend nvme controller cmd
Browse files Browse the repository at this point in the history
Signed-off-by: Artsiom Koltun <artsiom.koltun@intel.com>
  • Loading branch information
artek-koltun committed Feb 9, 2024
1 parent 86b40eb commit 5ce5a0a
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,12 @@ alias dpu="docker run --rm --network host ghcr.io/opiproject/godpu:main"
# connect to remote nvme/tcp controller
nvmf0=$(dpu storage create backend nvme controller --id nvmf0 --multipath disable)
path0=$(dpu storage create backend nvme path tcp --controller "$nvmf0" --id path0 --ip "11.11.11.2" --port 4444 --nqn nqn.2016-06.io.spdk:cnode1 --hostnqn nqn.2014-08.org.nvmexpress:uuid:feb98abe-d51f-40c8-b348-2753f3571d3c)
dpu storage get backend nvme controller --name $nvmf0

# connect to local nvme/pcie ssd controller
nvmf1=$(dpu storage create backend nvme controller --id nvmf1 --multipath disable)
path1=$(dpu storage create backend nvme path pcie --controller "$nvmf1" --id path1 --bdf "0000:40:00.0")
dpu storage get backend nvme controller --name $nvmf1

# expose volume over nvme/tcp controller
ss0=$(dpu storage create frontend nvme subsystem --id subsys0 --nqn "nqn.2022-09.io.spdk:opitest0")
Expand Down
35 changes: 35 additions & 0 deletions cmd/storage/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,38 @@ func newDeleteNvmeCommand() *cobra.Command {

return cmd
}

// NewGetCommand creates a new command to get backend resources
func NewGetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "backend",
Aliases: []string{"b"},
Short: "Gets backend resource",
Args: cobra.NoArgs,
Run: func(c *cobra.Command, args []string) {
err := c.Help()
cobra.CheckErr(err)
},
}

cmd.AddCommand(newGetNvmeCommand())

return cmd
}

func newGetNvmeCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "nvme",
Aliases: []string{"n"},
Short: "Gets nvme resource",
Args: cobra.NoArgs,
Run: func(c *cobra.Command, args []string) {
err := c.Help()
cobra.CheckErr(err)
},
}

cmd.AddCommand(newGetNvmeControllerCommand())

return cmd
}
35 changes: 35 additions & 0 deletions cmd/storage/backend/nvme_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
backendclient "github.com/opiproject/godpu/storage/backend"
pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/protojson"
)

func newCreateNvmeControllerCommand() *cobra.Command {
Expand Down Expand Up @@ -93,3 +94,37 @@ func newDeleteNvmeControllerCommand() *cobra.Command {

return cmd
}

func newGetNvmeControllerCommand() *cobra.Command {
name := ""
cmd := &cobra.Command{
Use: "controller",
Aliases: []string{"c"},
Short: "Gets nvme controller representing an external nvme device",
Args: cobra.NoArgs,
Run: func(c *cobra.Command, args []string) {
addr, err := c.Flags().GetString(common.AddrCmdLineArg)
cobra.CheckErr(err)

timeout, err := c.Flags().GetDuration(common.TimeoutCmdLineArg)
cobra.CheckErr(err)

client, err := backendclient.New(addr)
cobra.CheckErr(err)

ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

ctrl, err := client.GetNvmeController(ctx, name)
cobra.CheckErr(err)

common.PrintResponse(protojson.Format(ctrl))
},
}

cmd.Flags().StringVar(&name, "name", "", "name of remote controller to get")

cobra.CheckErr(cmd.MarkFlagRequired("name"))

return cmd
}
18 changes: 18 additions & 0 deletions cmd/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func NewStorageCommand() *cobra.Command {

cmd.AddCommand(newStorageCreateCommand())
cmd.AddCommand(newStorageDeleteCommand())
cmd.AddCommand(newStorageGetCommand())
cmd.AddCommand(newStorageTestCommand())

return cmd
Expand Down Expand Up @@ -72,3 +73,20 @@ func newStorageDeleteCommand() *cobra.Command {

return cmd
}

func newStorageGetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "get",
Aliases: []string{"g"},
Short: "Gets resource",
Args: cobra.NoArgs,
Run: func(c *cobra.Command, args []string) {
err := c.Help()
cobra.CheckErr(err)
},
}

cmd.AddCommand(backend.NewGetCommand())

return cmd
}
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ services:
command: |
'/dpu storage test --addr opi-spdk-server:50051 && \
nvmf0=$$(/dpu storage create backend nvme controller --addr=opi-spdk-server:50051 --id nvmf0 --multipath failover) && \
/dpu storage get backend nvme controller --addr=opi-spdk-server:50051 --name "$$nvmf0" && \
path0=$$(/dpu storage create backend nvme path tcp --addr=opi-spdk-server:50051 --controller "$$nvmf0" --id path0 --ip $$(getent hosts spdk | cut -d" " -f1) --port 4444 --nqn nqn.2016-06.io.spdk:cnode1 --hostnqn nqn.2014-08.org.nvmexpress:uuid:feb98abe-d51f-40c8-b348-2753f3571d3c) && \
ss0=$$(/dpu storage create frontend nvme subsystem --addr=opi-spdk-server:50051 --id subsys0 --nqn "nqn.2022-09.io.spdk:opitest1") && \
ctrl0=$$(/dpu storage create frontend nvme controller tcp --addr=opi-spdk-server:50051 --id ctrl0 --ip "127.0.0.1" --port 4420 --subsystem "$$ss0") && \
Expand Down
20 changes: 20 additions & 0 deletions storage/backend/nvme_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,23 @@ func (c *Client) DeleteNvmeController(

return err
}

// GetNvmeController gets an nvme controller representing
// an external nvme device
func (c *Client) GetNvmeController(
ctx context.Context,
name string,
) (*pb.NvmeRemoteController, error) {
conn, connClose, err := c.connector.NewConn()
if err != nil {
return nil, err
}
defer connClose()

client := c.createNvmeClient(conn)
return client.GetNvmeRemoteController(
ctx,
&pb.GetNvmeRemoteControllerRequest{
Name: name,
})
}
78 changes: 78 additions & 0 deletions storage/backend/nvme_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,81 @@ func TestDeleteNvmeController(t *testing.T) {
})
}
}

func TestGetNvmeController(t *testing.T) {
testControllerName := "remotenvme0"
testRequest := &pb.GetNvmeRemoteControllerRequest{
Name: testControllerName,
}
testController := &pb.NvmeRemoteController{
Name: testControllerName,
Multipath: pb.NvmeMultipath_NVME_MULTIPATH_FAILOVER,
}
tests := map[string]struct {
giveClientErr error
giveConnectorErr error
wantErr error
wantRequest *pb.GetNvmeRemoteControllerRequest
wantResponse *pb.NvmeRemoteController
wantConnClosed bool
}{
"successful call": {
giveConnectorErr: nil,
giveClientErr: nil,
wantErr: nil,
wantRequest: proto.Clone(testRequest).(*pb.GetNvmeRemoteControllerRequest),
wantResponse: proto.Clone(testController).(*pb.NvmeRemoteController),
wantConnClosed: true,
},
"client err": {
giveConnectorErr: nil,
giveClientErr: errors.New("Some client error"),
wantErr: errors.New("Some client error"),
wantRequest: proto.Clone(testRequest).(*pb.GetNvmeRemoteControllerRequest),
wantResponse: nil,
wantConnClosed: true,
},
"connector err": {
giveConnectorErr: errors.New("Some conn error"),
giveClientErr: nil,
wantErr: errors.New("Some conn error"),
wantRequest: nil,
wantResponse: nil,
wantConnClosed: false,
},
}

for testName, tt := range tests {
t.Run(testName, func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

mockClient := mocks.NewNvmeRemoteControllerServiceClient(t)
if tt.wantRequest != nil {
mockClient.EXPECT().GetNvmeRemoteController(ctx, tt.wantRequest).
Return(proto.Clone(tt.wantResponse).(*pb.NvmeRemoteController), tt.giveClientErr)
}

connClosed := false
mockConn := mocks.NewConnector(t)
mockConn.EXPECT().NewConn().Return(
&grpc.ClientConn{},
func() { connClosed = true },
tt.giveConnectorErr,
)

c, _ := NewWithArgs(
mockConn,
func(grpc.ClientConnInterface) pb.NvmeRemoteControllerServiceClient {
return mockClient
},
)

response, err := c.GetNvmeController(ctx, testControllerName)

require.Equal(t, tt.wantErr, err)
require.True(t, proto.Equal(tt.wantResponse, response))
require.Equal(t, tt.wantConnClosed, connClosed)
})
}
}

0 comments on commit 5ce5a0a

Please sign in to comment.