spiegel_podman/cmd/podman/machine/init.go
Brent Baude 833456e079 Add podman machine test suite
This PR introduces a test suite for podman machine.  It can currently be
run on developers' local machines and is not part of the official CI
testing; however, the expectation is that any work on machine should
come with an accompanying test.

At present, the test must be run on Linux.  It is untested on Darwin.
There is no Makefile target for the test.  It can be run like `ginkgo -v
pkg/machine/test/.`.  It should be run as a unprivileged user.

Signed-off-by: Brent Baude <bbaude@redhat.com>
2022-04-25 13:05:35 -05:00

162 lines
5 KiB
Go

//go:build amd64 || arm64
// +build amd64 arm64
package machine
import (
"fmt"
"os"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/machine"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
var (
initCmd = &cobra.Command{
Use: "init [options] [NAME]",
Short: "Initialize a virtual machine",
Long: "initialize a virtual machine ",
RunE: initMachine,
Args: cobra.MaximumNArgs(1),
Example: `podman machine init myvm`,
ValidArgsFunction: completion.AutocompleteNone,
}
)
var (
initOpts = machine.InitOptions{}
defaultMachineName = machine.DefaultMachineName
now bool
)
// maxMachineNameSize is set to thirty to limit huge machine names primarily
// because macos has a much smaller file size limit.
const maxMachineNameSize = 30
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Command: initCmd,
Parent: machineCmd,
})
flags := initCmd.Flags()
cfg := registry.PodmanConfig()
initOpts.Username = cfg.Config.Machine.User
cpusFlagName := "cpus"
flags.Uint64Var(
&initOpts.CPUS,
cpusFlagName, cfg.Machine.CPUs,
"Number of CPUs",
)
_ = initCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
diskSizeFlagName := "disk-size"
flags.Uint64Var(
&initOpts.DiskSize,
diskSizeFlagName, cfg.Machine.DiskSize,
"Disk size in GB",
)
_ = initCmd.RegisterFlagCompletionFunc(diskSizeFlagName, completion.AutocompleteNone)
memoryFlagName := "memory"
flags.Uint64VarP(
&initOpts.Memory,
memoryFlagName, "m", cfg.Machine.Memory,
"Memory in MB",
)
_ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
flags.BoolVar(
&now,
"now", false,
"Start machine now",
)
timezoneFlagName := "timezone"
defaultTz := cfg.TZ()
if len(defaultTz) < 1 {
defaultTz = "local"
}
flags.StringVar(&initOpts.TimeZone, timezoneFlagName, defaultTz, "Set timezone")
_ = initCmd.RegisterFlagCompletionFunc(timezoneFlagName, completion.AutocompleteDefault)
flags.BoolVar(
&initOpts.ReExec,
"reexec", false,
"process was rexeced",
)
_ = flags.MarkHidden("reexec")
ImagePathFlagName := "image-path"
flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Machine.Image, "Path to qcow image")
_ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
VolumeFlagName := "volume"
flags.StringArrayVarP(&initOpts.Volumes, VolumeFlagName, "v", cfg.Machine.Volumes, "Volumes to mount, source:target")
_ = initCmd.RegisterFlagCompletionFunc(VolumeFlagName, completion.AutocompleteDefault)
VolumeDriverFlagName := "volume-driver"
flags.StringVar(&initOpts.VolumeDriver, VolumeDriverFlagName, "", "Optional volume driver")
_ = initCmd.RegisterFlagCompletionFunc(VolumeDriverFlagName, completion.AutocompleteDefault)
IgnitionPathFlagName := "ignition-path"
flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file")
_ = initCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault)
rootfulFlagName := "rootful"
flags.BoolVar(&initOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")
}
// TODO should we allow for a users to append to the qemu cmdline?
func initMachine(cmd *cobra.Command, args []string) error {
var (
err error
vm machine.VM
)
provider := getSystemDefaultProvider()
initOpts.Name = defaultMachineName
if len(args) > 0 {
if len(args[0]) > maxMachineNameSize {
return errors.New("machine name must be 30 characters or less")
}
initOpts.Name = args[0]
}
if _, err := provider.LoadVMByName(initOpts.Name); err == nil {
return errors.Wrap(machine.ErrVMAlreadyExists, initOpts.Name)
}
for idx, vol := range initOpts.Volumes {
initOpts.Volumes[idx] = os.ExpandEnv(vol)
}
vm, err = provider.NewMachine(initOpts)
if err != nil {
return err
}
if finished, err := vm.Init(initOpts); err != nil || !finished {
// Finished = true, err = nil - Success! Log a message with further instructions
// Finished = false, err = nil - The installation is partially complete and podman should
// exit gracefully with no error and no success message.
// Examples:
// - a user has chosen to perform their own reboot
// - reexec for limited admin operations, returning to parent
// Finished = *, err != nil - Exit with an error message
return err
}
fmt.Println("Machine init complete")
if now {
err = vm.Start(initOpts.Name, machine.StartOptions{})
if err == nil {
fmt.Printf("Machine %q started successfully\n", initOpts.Name)
}
} else {
extra := ""
if initOpts.Name != defaultMachineName {
extra = " " + initOpts.Name
}
fmt.Printf("To start your machine run:\n\n\tpodman machine start%s\n\n", extra)
}
return err
}