Skip to content

Commit

Permalink
lxd/storage/backend: Notify instances following block custom volume r…
Browse files Browse the repository at this point in the history
…esize

Signed-off-by: Stéphane Graber <[email protected]>
(cherry picked from commit 81f9c4b915830322871bb49d6f04f3009f63d01a)
Signed-off-by: Kadin Sayani <[email protected]>
License: Apache-2.0
  • Loading branch information
stgraber authored and kadinsayani committed Oct 7, 2024
1 parent 8e62008 commit 4646696
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lxd/cluster/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ import (
"github.com/canonical/lxd/lxd/instance/instancetype"
"github.com/canonical/lxd/lxd/request"
"github.com/canonical/lxd/lxd/state"
storagePools "github.com/canonical/lxd/lxd/storage"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
"github.com/canonical/lxd/shared/version"
)

// Set references.
func init() {
storagePools.ConnectIfInstanceIsRemote = ConnectIfInstanceIsRemote
}

// Connect is a convenience around lxd.ConnectLXD that configures the client
// with the correct parameters for node-to-node communication.
//
Expand Down
81 changes: 81 additions & 0 deletions lxd/storage/backend_lxd.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ import (
"golang.org/x/sys/unix"
"gopkg.in/yaml.v2"

"github.com/canonical/lxd/client"
"github.com/canonical/lxd/lxd/apparmor"
"github.com/canonical/lxd/lxd/backup"
backupConfig "github.com/canonical/lxd/lxd/backup/config"
"github.com/canonical/lxd/lxd/cluster/request"
"github.com/canonical/lxd/lxd/db"
"github.com/canonical/lxd/lxd/db/cluster"
deviceConfig "github.com/canonical/lxd/lxd/device/config"
"github.com/canonical/lxd/lxd/instance"
"github.com/canonical/lxd/lxd/instance/instancetype"
"github.com/canonical/lxd/lxd/instancewriter"
Expand Down Expand Up @@ -64,6 +66,11 @@ import (
var unavailablePools = make(map[string]struct{})
var unavailablePoolsMu = sync.Mutex{}

// ConnectIfInstanceIsRemote is a reference to cluster.ConnectIfInstanceIsRemote.
//
//nolint:typecheck
var ConnectIfInstanceIsRemote func(s *state.State, projectName string, instName string, r *http.Request, instanceType instancetype.Type) (lxd.InstanceServer, error)

// instanceDiskVolumeEffectiveFields fields from the instance disks that are applied to the volume's effective
// config (but not stored in the disk's volume database record).
var instanceDiskVolumeEffectiveFields = []string{
Expand Down Expand Up @@ -6068,6 +6075,80 @@ func (b *lxdBackend) UpdateCustomVolume(projectName string, volName string, newD
delete(newConfig, "volatile.idmap.next")
}

// Notify instances of disk size changes as needed.
newSize, ok := changedConfig["size"]
if ok && newSize != "" && contentType == drivers.ContentTypeBlock {
// Get the disk size in bytes.
size, err := units.ParseByteSizeString(changedConfig["size"])
if err != nil {
return err
}

type instDevice struct {
args db.InstanceArgs
devices []string
}

instDevices := []instDevice{}
err = VolumeUsedByInstanceDevices(b.state, b.name, projectName, &curVol.StorageVolume, true, func(dbInst db.InstanceArgs, project api.Project, usedByDevices []string) error {
if dbInst.Type != instancetype.VM {
return nil
}

instDevices = append(instDevices, instDevice{args: dbInst, devices: usedByDevices})
return nil
})
if err != nil {
return err
}

for _, entry := range instDevices {
c, err := ConnectIfInstanceIsRemote(b.state, entry.args.Project, entry.args.Name, nil, entry.args.Type)
if err != nil {
return err
}

if c != nil {
// Send a remote notification.
devs := []string{}
for _, devName := range entry.devices {
devs = append(devs, fmt.Sprintf("%s:%d", devName, size))
}

uri := fmt.Sprintf("/internal/virtual-machines/%d/onresize?devices=%s", entry.args.ID, strings.Join(devs, ","))
_, _, err := c.RawQuery("GET", uri, nil, "")
if err != nil {
return err
}
} else {
// Update the local instance.
inst, err := instance.LoadByProjectAndName(b.state, entry.args.Project, entry.args.Name)
if err != nil {
return err
}

if !inst.IsRunning() {
continue
}

for _, devName := range entry.devices {
runConf := deviceConfig.RunConfig{}
runConf.Mounts = []deviceConfig.MountEntryItem{
{
DevName: devName,
Size: size,
},
}

err = inst.DeviceEventHandler(&runConf)
if err != nil {
return err
}
}
}
}
}

// Update the database if something changed.
if len(changedConfig) != 0 || newDesc != curVol.Description {
err = b.state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
Expand Down

0 comments on commit 4646696

Please sign in to comment.