Skip to content

Commit

Permalink
Merge pull request #13603 from tomponline/tp-vm-disk
Browse files Browse the repository at this point in the history
Device: Support long device names for host path passthrough to VMs
  • Loading branch information
tomponline authored Jun 17, 2024
2 parents 1fef3c5 + 1b914b4 commit e5d61c0
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 155 deletions.
12 changes: 9 additions & 3 deletions lxd-agent/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/canonical/lxd/lxd/events"
"github.com/canonical/lxd/lxd/instance/instancetype"
"github.com/canonical/lxd/lxd/response"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
Expand All @@ -27,6 +28,7 @@ type eventsServe struct {
d *Daemon
}

// Render starts event socket.
func (r *eventsServe) Render(w http.ResponseWriter) error {
return eventsSocket(r.d, r.req, w)
}
Expand Down Expand Up @@ -115,9 +117,10 @@ func eventsProcess(event api.Event) {
}

type deviceEvent struct {
Action string `json:"action"`
Config map[string]string `json:"config"`
Name string `json:"name"`
Action string `json:"action"`
Config map[string]string `json:"config"`
Name string `json:"name"`
Mount instancetype.VMAgentMount `json:"mount"`
}

e := deviceEvent{}
Expand All @@ -143,6 +146,9 @@ func eventsProcess(event api.Event) {

// Attempt to perform the mount.
mntSource := fmt.Sprintf("lxd_%s", e.Name)
if e.Mount.Source != "" {
mntSource = e.Mount.Source
}

_ = os.MkdirAll(e.Config["path"], 0755)
_, err = shared.RunCommand("mount", "-t", "virtiofs", mntSource, e.Config["path"])
Expand Down
8 changes: 4 additions & 4 deletions lxd/device/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,15 +850,15 @@ func (d *disk) startContainer() (*deviceConfig.RunConfig, error) {

// vmVirtfsProxyHelperPaths returns the path for PID file to use with virtfs-proxy-helper process.
func (d *disk) vmVirtfsProxyHelperPaths() string {
pidPath := filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("%s.pid", d.name))
pidPath := filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("%s.pid", filesystem.PathNameEncode(d.name)))

return pidPath
}

// vmVirtiofsdPaths returns the path for the socket and PID file to use with virtiofsd process.
func (d *disk) vmVirtiofsdPaths() (sockPath string, pidPath string) {
sockPath = filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("virtio-fs.%s.sock", d.name))
pidPath = filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("virtio-fs.%s.pid", d.name))
sockPath = filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("virtio-fs.%s.sock", filesystem.PathNameEncode(d.name)))
pidPath = filepath.Join(d.inst.DevicesPath(), fmt.Sprintf("virtio-fs.%s.pid", filesystem.PathNameEncode(d.name)))

return sockPath, pidPath
}
Expand Down Expand Up @@ -1114,7 +1114,7 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
// virtfs-proxy-helper 9p share. The 9p share will only be used as a fallback.
err = func() error {
sockPath, pidPath := d.vmVirtiofsdPaths()
logPath := filepath.Join(d.inst.LogPath(), fmt.Sprintf("disk.%s.log", d.name))
logPath := filepath.Join(d.inst.LogPath(), fmt.Sprintf("disk.%s.log", filesystem.PathNameEncode(d.name)))
_ = os.Remove(logPath) // Remove old log if needed.

revertFunc, unixListener, err := DiskVMVirtiofsdStart(d.state.OS.ExecPath, d.inst, sockPath, pidPath, logPath, mount.DevPath, rawIDMaps)
Expand Down
57 changes: 44 additions & 13 deletions lxd/instance/drivers/driver_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -1419,13 +1419,13 @@ func (d *common) devicesRegister(inst instance.Instance) {
}

// devicesUpdate applies device changes to an instance.
func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfig.Devices, addDevices deviceConfig.Devices, updateDevices deviceConfig.Devices, oldExpandedDevices deviceConfig.Devices, instanceRunning bool, userRequested bool) error {
func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfig.Devices, addDevices deviceConfig.Devices, updateDevices deviceConfig.Devices, oldExpandedDevices deviceConfig.Devices, instanceRunning bool, userRequested bool) (devlxdEvents []map[string]any, err error) {
revert := revert.New()
defer revert.Fail()

dm, ok := inst.(deviceManager)
if !ok {
return fmt.Errorf("Instance is not compatible with deviceManager interface")
return nil, fmt.Errorf("Instance is not compatible with deviceManager interface")
}

// Remove devices in reverse order to how they were added.
Expand All @@ -1446,13 +1446,19 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
if instanceRunning {
err = dm.deviceStop(dev, instanceRunning, "")
if err != nil {
return fmt.Errorf("Failed to stop device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed to stop device %q: %w", dev.Name(), err)
}

devlxdEvents = append(devlxdEvents, map[string]any{
"action": "removed",
"name": entry.Name,
"config": entry.Config,
})
}

err = d.deviceRemove(dev, instanceRunning)
if err != nil && err != device.ErrUnsupportedDevType {
return fmt.Errorf("Failed to remove device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed to remove device %q: %w", dev.Name(), err)
}
}

Expand All @@ -1461,7 +1467,7 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
// this device (as its an actual removal or a device type change).
err = d.deviceVolatileReset(entry.Name, entry.Config, addDevices[entry.Name])
if err != nil {
return fmt.Errorf("Failed to reset volatile data for device %q: %w", entry.Name, err)
return nil, fmt.Errorf("Failed to reset volatile data for device %q: %w", entry.Name, err)
}
}

Expand All @@ -1475,7 +1481,7 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
}

if userRequested {
return fmt.Errorf("Failed add validation for device %q: %w", entry.Name, err)
return nil, fmt.Errorf("Failed add validation for device %q: %w", entry.Name, err)
}

// If update is non-user requested (i.e from a snapshot restore), there's nothing we can
Expand All @@ -1488,7 +1494,7 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
err = d.deviceAdd(dev, instanceRunning)
if err != nil {
if userRequested {
return fmt.Errorf("Failed to add device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed to add device %q: %w", dev.Name(), err)
}

// If update is non-user requested (i.e from a snapshot restore), there's nothing we can
Expand All @@ -1501,15 +1507,34 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
if instanceRunning {
err = dev.PreStartCheck()
if err != nil {
return fmt.Errorf("Failed pre-start check for device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed pre-start check for device %q: %w", dev.Name(), err)
}

_, err := dm.deviceStart(dev, instanceRunning)
runConf, err := dm.deviceStart(dev, instanceRunning)
if err != nil && err != device.ErrUnsupportedDevType {
return fmt.Errorf("Failed to start device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed to start device %q: %w", dev.Name(), err)
}

revert.Add(func() { _ = dm.deviceStop(dev, instanceRunning, "") })

event := map[string]any{
"action": "added",
"name": entry.Name,
"config": entry.Config,
}

if len(runConf.Mounts) > 0 {
for _, opt := range runConf.Mounts[0].Opts {
if strings.HasPrefix(opt, "mountTag=") {
parts := strings.SplitN(opt, "=", 2)
event["mount"] = instancetype.VMAgentMount{
Source: parts[1],
}
}
}
}

devlxdEvents = append(devlxdEvents, event)
}
}

Expand All @@ -1522,7 +1547,7 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
}

if userRequested {
return fmt.Errorf("Failed update validation for device %q: %w", entry.Name, err)
return nil, fmt.Errorf("Failed update validation for device %q: %w", entry.Name, err)
}

// If update is non-user requested (i.e from a snapshot restore), there's nothing we can
Expand All @@ -1542,6 +1567,12 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi
if err != nil {
l.Error("Failed to stop device after update validation failed", logger.Ctx{"err": err})
}

devlxdEvents = append(devlxdEvents, map[string]any{
"action": "updated",
"name": entry.Name,
"config": entry.Config,
})
}

err = d.deviceRemove(dev, instanceRunning)
Expand All @@ -1555,12 +1586,12 @@ func (d *common) devicesUpdate(inst instance.Instance, removeDevices deviceConfi

err = dev.Update(oldExpandedDevices, instanceRunning)
if err != nil {
return fmt.Errorf("Failed to update device %q: %w", dev.Name(), err)
return nil, fmt.Errorf("Failed to update device %q: %w", dev.Name(), err)
}
}

revert.Success()
return nil
return devlxdEvents, nil
}

// devicesRemove runs device removal function for each device.
Expand Down
40 changes: 4 additions & 36 deletions lxd/instance/drivers/driver_lxc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4384,7 +4384,7 @@ func (d *lxc) Update(args db.InstanceArgs, userRequested bool) error {
isRunning := d.IsRunning()

// Use the device interface to apply update changes.
err = d.devicesUpdate(d, removeDevices, addDevices, updateDevices, oldExpandedDevices, isRunning, userRequested)
devlxdEvents, err := d.devicesUpdate(d, removeDevices, addDevices, updateDevices, oldExpandedDevices, isRunning, userRequested)
if err != nil {
return err
}
Expand Down Expand Up @@ -4819,41 +4819,9 @@ func (d *lxc) Update(args db.InstanceArgs, userRequested bool) error {
}
}

// Device changes
for k, m := range removeDevices {
msg := map[string]any{
"action": "removed",
"name": k,
"config": m,
}

err = d.devlxdEventSend("device", msg)
if err != nil {
return err
}
}

for k, m := range updateDevices {
msg := map[string]any{
"action": "updated",
"name": k,
"config": m,
}

err = d.devlxdEventSend("device", msg)
if err != nil {
return err
}
}

for k, m := range addDevices {
msg := map[string]any{
"action": "added",
"name": k,
"config": m,
}

err = d.devlxdEventSend("device", msg)
// Device events.
for _, event := range devlxdEvents {
err = d.devlxdEventSend("device", event)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit e5d61c0

Please sign in to comment.