func growContainerCommand()

in internal/cmd/grow_container.go [33:93]


func growContainerCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "grow",
		Short: "resize container to max size",
		Long: strings.TrimSpace(`
grow resizes the container to its maximum size using
'diskutil'. The container to operate on can be specified
with its identifier (e.g. disk1 or /dev/disk1). The string
'root' may be provided to resize the OS's root volume.
		`),
	}

	// Set up the flags to be passed into the command
	growArgs := growContainer{}
	cmd.PersistentFlags().StringVar(&growArgs.id, "id", "", `container identifier to be resized or "root"`)
	cmd.PersistentFlags().BoolVar(&growArgs.dryrun, "dry-run", false, "run command without mutating changes")
	cmd.PersistentFlags().DurationVar(&growArgs.timeout, "timeout", growDefaultTimeout, "Set the timeout for the command (e.g. 30s, 1m, 1.5h), 0s will disable the timeout")
	_ = cmd.MarkPersistentFlagRequired("id")

	// Set up the command's pre-run to check for root permissions.
	// This is necessary since diskutil repairDisk requires root permissions to run.
	cmd.PreRunE = assertRootPrivileges

	// Set up the command's run function
	cmd.RunE = func(cmd *cobra.Command, args []string) error {
		ctx := cmd.Context()
		if growArgs.timeout > 0 {
			timeoutBoundCtx, cancel := context.WithTimeout(ctx, growArgs.timeout)
			defer cancel()
			ctx = timeoutBoundCtx
		}

		product := contextual.Product(ctx)
		if product == nil {
			return errors.New("product required in context")
		}

		logrus.WithField("product", product).Info("Configuring diskutil for product")
		d, err := diskutil.ForProduct(product)
		if err != nil {
			return err
		}

		if growArgs.dryrun {
			d = diskutil.Dryrun(d)
		}

		logrus.WithField("args", growArgs).Debug("Running grow command with args")
		if err := run(ctx, d, growArgs); err != nil {
			if ctx.Err() == context.DeadlineExceeded {
				return errors.New("timeout exceeded")
			}

			return err
		}

		return nil
	}

	return cmd
}