Skip to content

Commit

Permalink
lxd/storage_volume: Factor volume attach arg parsing
Browse files Browse the repository at this point in the history
Bring the fix from #13258 to `lxc storage volume attach-profile`

Signed-off-by: Wesley Hershberger <[email protected]>
  • Loading branch information
MggMuggins committed Feb 14, 2025
1 parent 15ce225 commit 3b6a98c
Showing 1 changed file with 64 additions and 106 deletions.
170 changes: 64 additions & 106 deletions lxc/storage_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,68 @@ func (c *cmdStorageVolume) parseVolumeWithPool(name string) (volumeName string,
return fields[1], fields[0]
}

func cmdAttachArgsAsDevice(client lxd.InstanceServer, poolName string, flagTarget string, args []string) (devName string, device map[string]string, err error) {
volName, volType, snapshot := parseVolumeSnapshot("custom", args[1])
if volType != "custom" && volType != "virtual-machine" {
return "", nil, errors.New(i18n.G(`Only "custom" and "virtual-machine" volumes can be attached to instances`))
}

// Attach the volume
devPath := ""
if len(args) == 3 {
devName = args[1]
} else if len(args) == 4 {
// Use the provided target.
if flagTarget != "" && client.IsClustered() {
client = client.UseTarget(flagTarget)
}

vol, _, err := client.GetStoragePoolVolume(poolName, volType, volName)
if err != nil {
return "", nil, err
}

switch vol.ContentType {
case "block", "iso":
devName = args[3]
case "filesystem":
// If using a filesystem volume, the path must also be provided as the fourth argument.
if !strings.HasPrefix(args[3], "/") {
devPath = path.Join("/", args[3])
} else {
devPath = args[3]
}

devName = args[1]
default:
return "", nil, errors.New(i18n.G("Unsupported content type for attaching to instances"))
}
} else if len(args) == 5 {
// Path and device name have been given to us.
devName = args[3]
devPath = args[4]
}

// Prepare the instance's device entry
device = map[string]string{
"type": "disk",
"pool": poolName,
"source": volName,
"path": devPath,
}

// Only specify sourcetype when not the default
if volType != "custom" {
device["source-type"] = volType
}

if snapshot != "" {
device["source.snapshot"] = snapshot
}

return devName, device, nil
}

// Attach.
type cmdStorageVolumeAttach struct {
global *cmdGlobal
Expand Down Expand Up @@ -222,66 +284,7 @@ func (c *cmdStorageVolumeAttach) run(cmd *cobra.Command, args []string) error {
return errors.New(i18n.G("Missing pool name"))
}

volName, volType, snapshot := parseVolumeSnapshot("custom", args[1])
if volType != "custom" && volType != "virtual-machine" {
return errors.New(i18n.G(`Only "custom" and "virtual-machine" volumes can be attached to instances`))
}

// Attach the volume
devPath := ""
devName := ""
if len(args) == 3 {
devName = args[1]
} else if len(args) == 4 {
client := resource.server

// Use the provided target.
if c.storage.flagTarget != "" && client.IsClustered() {
client = client.UseTarget(c.storage.flagTarget)
}

vol, _, err := client.GetStoragePoolVolume(resource.name, volType, volName)
if err != nil {
return err
}

switch vol.ContentType {
case "block", "iso":
devName = args[3]
case "filesystem":
// If using a filesystem volume, the path must also be provided as the fourth argument.
if !strings.HasPrefix(args[3], "/") {
devPath = path.Join("/", args[3])
} else {
devPath = args[3]
}

devName = args[1]
default:
return errors.New(i18n.G("Unsupported content type for attaching to instances"))
}
} else if len(args) == 5 {
// Path and device name have been given to us.
devName = args[3]
devPath = args[4]
}

// Prepare the instance's device entry
device := map[string]string{
"type": "disk",
"pool": resource.name,
"source": volName,
"path": devPath,
}

// Only specify sourcetype when not the default
if volType != "custom" {
device["source-type"] = volType
}

if snapshot != "" {
device["source.snapshot"] = snapshot
}
devName, device, err := cmdAttachArgsAsDevice(resource.server, resource.name, c.storage.flagTarget, args)

// Add the device to the instance
err = instanceDeviceAdd(resource.server, args[2], devName, device)
Expand Down Expand Up @@ -348,52 +351,7 @@ func (c *cmdStorageVolumeAttachProfile) run(cmd *cobra.Command, args []string) e
return errors.New(i18n.G("Missing pool name"))
}

// Attach the volume
devPath := ""
devName := ""
if len(args) == 3 {
devName = args[1]
} else if len(args) == 4 {
// Only the path has been given to us.
devPath = args[3]
devName = args[1]
} else if len(args) == 5 {
// Path and device name have been given to us.
devName = args[3]
devPath = args[4]
}

volName, volType, snapshot := parseVolumeSnapshot("custom", args[1])
if volType != "custom" && volType != "virtual-machine" {
return errors.New(i18n.G(`Only "custom" and "virtual-machine" volumes can be attached to profiles`))
}

// Check if the requested storage volume actually exists
vol, _, err := resource.server.GetStoragePoolVolume(resource.name, volType, volName)
if err != nil {
return err
}

// Prepare the instance's device entry
device := map[string]string{
"type": "disk",
"pool": resource.name,
"source": volName,
}

// Ignore path for block volumes
if vol.ContentType != "block" {
device["path"] = devPath
}

// Only specify sourcetype when not the default
if volType != "custom" {
device["source-type"] = volType
}

if snapshot != "" {
device["source.snapshot"] = snapshot
}
devName, device, err := cmdAttachArgsAsDevice(resource.server, resource.name, c.storage.flagTarget, args)

// Add the device to the instance
err = profileDeviceAdd(resource.server, args[2], devName, device)
Expand Down

0 comments on commit 3b6a98c

Please sign in to comment.