diff --git a/app/cmd/basic/bdev_lvol.go b/app/cmd/basic/bdev_lvol.go index 608681cd..5815565a 100644 --- a/app/cmd/basic/bdev_lvol.go +++ b/app/cmd/basic/bdev_lvol.go @@ -32,6 +32,7 @@ func BdevLvolCmd() cli.Command { BdevLvolCheckShallowCopyCmd(), BdevLvolGetXattrCmd(), BdevLvolGetFragmapCmd(), + BdevLvolRenameCmd(), }, } } @@ -605,3 +606,51 @@ func bdevLvolGetFragmap(c *cli.Context) error { return util.PrintObject(output) } + +func BdevLvolRenameCmd() cli.Command { + return cli.Command{ + Name: "rename", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "old-name", + Usage: "The UUID or alias (/) of the existing logical volume", + Required: true, + }, + cli.StringFlag{ + Name: "new-name", + Usage: "New logical volume name.", + Required: true, + }, + }, + Usage: "Rename a logical volume. New name will rename only the alias of the logical volume: \"rename --old-name / --new-name \" or \"rename --old-name --new-name \"", + Action: func(c *cli.Context) { + if err := bdevLvolRename(c); err != nil { + logrus.WithError(err).Fatalf("Failed to run rename bdev lvol command") + } + }, + } +} + +func bdevLvolRename(c *cli.Context) error { + spdkCli, err := client.NewClient(context.Background()) + if err != nil { + return err + } + + oldName := c.String("old-name") + newName := c.String("new-name") + + if oldName == "" || newName == "" { + return fmt.Errorf("both old-name and new-name must be provided") + } + if oldName == newName { + return fmt.Errorf("old-name and new-name must be different") + } + + renamed, err := spdkCli.BdevLvolRename(oldName, newName) + if err != nil { + return fmt.Errorf("failed to rename logical volume from %q to %q: %v", oldName, newName, err) + } + + return util.PrintObject(renamed) +} diff --git a/pkg/spdk/client/basic.go b/pkg/spdk/client/basic.go index 96e35202..e257dabb 100644 --- a/pkg/spdk/client/basic.go +++ b/pkg/spdk/client/basic.go @@ -502,6 +502,26 @@ func (c *Client) BdevLvolGetFragmap(name string, offset, size uint64) (*spdktype return &result, nil } +// BdevLvolRename renames a logical volume. +// +// "oldName": Required. UUID or alias of the existing logical volume. +// +// "newName": Required. New logical volume name. +func (c *Client) BdevLvolRename(oldName, newName string) (renamed bool, err error) { + req := spdktypes.BdevLvolRenameRequest{ + OldName: oldName, + NewName: newName, + } + + cmdOutput, err := c.jsonCli.SendCommandWithLongTimeout("bdev_lvol_rename", req) + if err != nil { + return false, err + } + + err = json.Unmarshal(cmdOutput, &renamed) + return renamed, err +} + // BdevRaidCreate constructs a new RAID bdev. // // "name": Required. a RAID bdev name rather than an alias or a UUID. diff --git a/pkg/spdk/spdk_test.go b/pkg/spdk/spdk_test.go index a44d5b3a..9a433495 100644 --- a/pkg/spdk/spdk_test.go +++ b/pkg/spdk/spdk_test.go @@ -218,7 +218,8 @@ func (s *TestSuite) TestSPDKBasic(c *C) { c.Assert(snapLvol1.DriverSpecific.Lvol.Xattrs[client.UserCreated], Equals, "true") c.Assert(snapLvol1.DriverSpecific.Lvol.Xattrs[client.SnapshotTimestamp], Equals, snapshotTimestamp) - cloneLvolUUID1, err := spdkCli.BdevLvolClone(snapLvolUUID1, "clone111") + cloneName1 := "clone111" + cloneLvolUUID1, err := spdkCli.BdevLvolClone(snapLvolUUID1, cloneName1) c.Assert(err, IsNil) defer func() { deleted, err := spdkCli.BdevLvolDelete(cloneLvolUUID1) @@ -229,6 +230,8 @@ func (s *TestSuite) TestSPDKBasic(c *C) { c.Assert(err, IsNil) c.Assert(len(lvolList), Equals, 1) cloneLvol1 := lvolList[0] + c.Assert(len(cloneLvol1.Aliases), Equals, 1) + c.Assert(cloneLvol1.Aliases[0], Equals, spdktypes.GetLvolAlias(lvsName, cloneName1)) c.Assert(cloneLvol1.CreationTime, Not(Equals), "") c.Assert(cloneLvol1.DriverSpecific.Lvol, NotNil) c.Assert(cloneLvol1.DriverSpecific.Lvol.Snapshot, Equals, false) @@ -236,6 +239,18 @@ func (s *TestSuite) TestSPDKBasic(c *C) { c.Assert(cloneLvol1.DriverSpecific.Lvol.Xattrs[client.UserCreated], Equals, "true") c.Assert(cloneLvol1.DriverSpecific.Lvol.Xattrs[client.SnapshotTimestamp], Equals, "") + cloneRenamed1 := "clone111-tmp" + renamed, err := spdkCli.BdevLvolRename(cloneLvolUUID1, cloneRenamed1) + c.Assert(err, IsNil) + c.Assert(renamed, Equals, true) + lvolList, err = spdkCli.BdevLvolGet(cloneLvolUUID1, 0) + c.Assert(err, IsNil) + c.Assert(len(lvolList), Equals, 1) + cloneLvol1Renamed := lvolList[0] + c.Assert(len(cloneLvol1Renamed.Aliases), Equals, 1) + c.Assert(cloneLvol1Renamed.Aliases[0], Equals, spdktypes.GetLvolAlias(lvsName, cloneRenamed1)) + c.Assert(cloneLvol1Renamed.CreationTime, Equals, cloneLvol1.CreationTime) + decoupled, err := spdkCli.BdevLvolDecoupleParent(cloneLvolUUID1) c.Assert(err, IsNil) c.Assert(decoupled, Equals, true) diff --git a/pkg/spdk/types/lvol.go b/pkg/spdk/types/lvol.go index b79efa7c..a246b4f2 100644 --- a/pkg/spdk/types/lvol.go +++ b/pkg/spdk/types/lvol.go @@ -145,6 +145,11 @@ type BdevLvolGetFragmapRequest struct { Size uint64 `json:"size"` } +type BdevLvolRenameRequest struct { + OldName string `json:"old_name"` + NewName string `json:"new_name"` +} + func GetLvolAlias(lvsName, lvolName string) string { return fmt.Sprintf("%s/%s", lvsName, lvolName) }