in internal/diskutil/grow.go [20:80]
func GrowContainer(ctx context.Context, u DiskUtil, container *types.DiskInfo) error {
if container == nil {
return fmt.Errorf("unable to resize nil container")
}
logrus.WithField("device_id", container.DeviceIdentifier).Info("Checking if device can be APFS resized...")
if err := canAPFSResize(container); err != nil {
return fmt.Errorf("unable to resize container: %w", err)
}
logrus.Info("Device can be resized")
// We'll need to mutate the container's underlying physical disk, so resolve that if that's not what we have
// (which is basically guaranteed to not have physical disk for container resizes, should be the virtual APFS
// container).
phy := container
if !phy.IsPhysical() {
parent, err := u.Info(ctx, phy.ParentWholeDisk)
if err != nil {
return fmt.Errorf("unable to determine physical disk: %w", err)
}
// using the parent disk of provided disk (probably a container)
phy = parent
}
// Capture any free space on a resized disk
logrus.Info("Repairing the parent disk...")
_, err := repairParentDisk(ctx, u, phy)
if err != nil {
return fmt.Errorf("cannot update free space on disk: %w", err)
}
logrus.Info("Successfully repaired the parent disk")
// Minimum free space to resize required - bail if we don't have enough.
logrus.WithField("device_id", phy.DeviceIdentifier).Info("Fetching amount of free space on device...")
totalFree, err := getDiskFreeSpace(ctx, u, phy)
if err != nil {
return fmt.Errorf("cannot determine available space on disk: %w", err)
}
logrus.WithField("freed_bytes", humanize.Bytes(totalFree)).Trace("updated free space on disk")
if totalFree < minimumGrowFreeSpace {
logrus.WithFields(logrus.Fields{
"total_free": humanize.Bytes(totalFree),
"required_minimum": humanize.Bytes(minimumGrowFreeSpace),
}).Warn("Available free space does not meet required minimum to grow")
return fmt.Errorf("not enough space to resize container: %w", FreeSpaceError{totalFree})
}
logrus.WithFields(logrus.Fields{
"device_id": phy.DeviceIdentifier,
"free_space": humanize.Bytes(totalFree),
}).Info("Resizing container to maximum size...")
out, err := u.ResizeContainer(ctx, phy.DeviceIdentifier, "0")
logrus.WithField("out", out).Debug("Resize output")
if errors.Is(err, ErrReadOnly) {
logrus.WithError(err).Warn("Would have resized container to max size")
} else if err != nil {
return err
}
return nil
}