Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(storage/nvme): add cli for backend nvme path #433

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/storage/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func newCreateNvmeCommand() *cobra.Command {
}

cmd.AddCommand(newCreateNvmeControllerCommand())
cmd.AddCommand(newCreateNvmePathCommand())

return cmd
}
Expand Down Expand Up @@ -72,6 +73,7 @@ func newDeleteNvmeCommand() *cobra.Command {
}

cmd.AddCommand(newDeleteNvmeControllerCommand())
cmd.AddCommand(newDeleteNvmePathCommand())

return cmd
}
152 changes: 152 additions & 0 deletions cmd/storage/backend/nvme_path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2024 Intel Corporation

// Package backend implements the CLI commands for storage backend
package backend

import (
"context"
"net"

"github.com/opiproject/godpu/cmd/storage/common"
backendclient "github.com/opiproject/godpu/storage/backend"
"github.com/spf13/cobra"
)

func newCreateNvmePathCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "path",
Aliases: []string{"p"},
Short: "Creates nvme path to an external nvme device",
Args: cobra.NoArgs,
Run: func(c *cobra.Command, args []string) {
err := c.Help()
cobra.CheckErr(err)
},
}

cmd.AddCommand(newCreateNvmePathTCPCommand())
cmd.AddCommand(newCreateNvmePathPcieCommand())

return cmd
}

func newCreateNvmePathTCPCommand() *cobra.Command {
id := ""
nqn := ""
hostnqn := ""
controller := ""
var ip net.IP
var port uint16
cmd := &cobra.Command{
Use: "tcp",
Aliases: []string{"t"},
Short: "Creates nvme path to a remote nvme TCP controller",
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()

response, err := client.CreateNvmeTCPPath(ctx, id, controller, ip, port, nqn, hostnqn)
cobra.CheckErr(err)

common.PrintResponse(response.Name)
},
}

cmd.Flags().StringVar(&id, "id", "", "id for created resource. Assigned by server if omitted.")
cmd.Flags().StringVar(&controller, "controller", "", "backend controller name for this path")
cmd.Flags().IPVar(&ip, "ip", nil, "ip address of the path to connect to.")
cmd.Flags().Uint16Var(&port, "port", 0, "port of the path to connect to.")
cmd.Flags().StringVar(&nqn, "nqn", "", "nqn of the target subsystem.")
cmd.Flags().StringVar(&hostnqn, "hostnqn", "", "host nqn")

cobra.CheckErr(cmd.MarkFlagRequired("controller"))
cobra.CheckErr(cmd.MarkFlagRequired("ip"))
cobra.CheckErr(cmd.MarkFlagRequired("port"))
cobra.CheckErr(cmd.MarkFlagRequired("nqn"))

return cmd
}

func newCreateNvmePathPcieCommand() *cobra.Command {
id := ""
controller := ""
bdf := ""
cmd := &cobra.Command{
Use: "pcie",
Aliases: []string{"p"},
Short: "Creates nvme path to PCIe controller",
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()

response, err := client.CreateNvmePciePath(ctx, id, controller, bdf)
cobra.CheckErr(err)

common.PrintResponse(response.Name)
},
}

cmd.Flags().StringVar(&id, "id", "", "id for created resource. Assigned by server if omitted.")
cmd.Flags().StringVar(&controller, "controller", "", "backend controller name for this path")
cmd.Flags().StringVar(&bdf, "bdf", "", "bdf PCI address of NVMe/PCIe controller")

cobra.CheckErr(cmd.MarkFlagRequired("controller"))
cobra.CheckErr(cmd.MarkFlagRequired("bdf"))

return cmd
}

func newDeleteNvmePathCommand() *cobra.Command {
name := ""
allowMissing := false
cmd := &cobra.Command{
Use: "path",
Aliases: []string{"p"},
Short: "Deletes nvme path to 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()

err = client.DeleteNvmePath(ctx, name, allowMissing)
cobra.CheckErr(err)
},
}

cmd.Flags().StringVar(&name, "name", "", "name of deleted nvme path")
cmd.Flags().BoolVar(&allowMissing, "allowMissing", false, "cmd succeeds if attempts to delete a resource that is not present")

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

return cmd
}
110 changes: 110 additions & 0 deletions storage/backend/nvme_path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2024 Intel Corporation

// Package backend implements the go library for OPI backend storage
package backend

import (
"context"
"fmt"
"net"

pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go"
)

// CreateNvmeTCPPath creates a path to nvme TCP controller
func (c *Client) CreateNvmeTCPPath(
ctx context.Context,
id string,
controller string,
ip net.IP,
port uint16,
nqn, hostnqn string,
) (*pb.NvmePath, error) {
var adrfam pb.NvmeAddressFamily
switch {
case ip.To4() != nil:
adrfam = pb.NvmeAddressFamily_NVME_ADDRESS_FAMILY_IPV4
case ip.To16() != nil:
adrfam = pb.NvmeAddressFamily_NVME_ADDRESS_FAMILY_IPV6
default:
return nil, fmt.Errorf("invalid ip address format: %v", ip)
}

conn, connClose, err := c.connector.NewConn()
if err != nil {
return nil, err
}
defer connClose()

client := c.createNvmeClient(conn)
response, err := client.CreateNvmePath(
ctx,
&pb.CreateNvmePathRequest{
NvmePathId: id,
Parent: controller,
NvmePath: &pb.NvmePath{
Trtype: pb.NvmeTransportType_NVME_TRANSPORT_TYPE_TCP,
Traddr: ip.String(),
Fabrics: &pb.FabricsPath{
Trsvcid: int64(port),
Subnqn: nqn,
Adrfam: adrfam,
Hostnqn: hostnqn,
},
},
})

return response, err
}

// CreateNvmePciePath creates a path to nvme PCIe controller
func (c *Client) CreateNvmePciePath(
ctx context.Context,
id string,
controller string,
bdf string,
) (*pb.NvmePath, error) {
conn, connClose, err := c.connector.NewConn()
if err != nil {
return nil, err
}
defer connClose()

client := c.createNvmeClient(conn)
response, err := client.CreateNvmePath(
ctx,
&pb.CreateNvmePathRequest{
NvmePathId: id,
Parent: controller,
NvmePath: &pb.NvmePath{
Trtype: pb.NvmeTransportType_NVME_TRANSPORT_TYPE_PCIE,
Traddr: bdf,
},
})

return response, err
}

// DeleteNvmePath deletes an nvme path to an external nvme controller
func (c *Client) DeleteNvmePath(
ctx context.Context,
name string,
allowMissing bool,
) error {
conn, connClose, err := c.connector.NewConn()
if err != nil {
return err
}
defer connClose()

client := c.createNvmeClient(conn)
_, err = client.DeleteNvmePath(
ctx,
&pb.DeleteNvmePathRequest{
Name: name,
AllowMissing: allowMissing,
})

return err
}
Loading
Loading