func GrowContainer()

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
}