summaryrefslogtreecommitdiff
path: root/cmd/podman/machine
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2021-03-15 14:52:43 -0500
committerbaude <bbaude@redhat.com>2021-03-25 08:43:51 -0500
commitb5f54a9b23e8d9418700494da9aa78d8db354c43 (patch)
tree59dfb9edf3faf6d184f6af40522f71968948133a /cmd/podman/machine
parenta861f6fd3ebe4fe0b63a1b550e6b99d7525228c0 (diff)
downloadpodman-b5f54a9b23e8d9418700494da9aa78d8db354c43.tar.gz
podman-b5f54a9b23e8d9418700494da9aa78d8db354c43.tar.bz2
podman-b5f54a9b23e8d9418700494da9aa78d8db354c43.zip
introduce podman machine
podman machine allows podman to create, manage, and interact with a vm running some form of linux (default is fcos). podman is then configured to be able to interact with the vm automatically. while this is usable on linux, the real push is to get this working on both current apple architectures in macos. Ashley Cui contributed to this PR and was a great help. [NO TESTS NEEDED] Signed-off-by: baude <bbaude@redhat.com>
Diffstat (limited to 'cmd/podman/machine')
-rw-r--r--cmd/podman/machine/config.go38
-rw-r--r--cmd/podman/machine/create.go119
-rw-r--r--cmd/podman/machine/destroy.go91
-rw-r--r--cmd/podman/machine/ssh.go47
-rw-r--r--cmd/podman/machine/start.go18
-rw-r--r--cmd/podman/machine/stop.go19
6 files changed, 216 insertions, 116 deletions
diff --git a/cmd/podman/machine/config.go b/cmd/podman/machine/config.go
deleted file mode 100644
index 5fa6aa50d..000000000
--- a/cmd/podman/machine/config.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package machine
-
-import "fmt"
-
-type CreateOptions struct {
- CPUS uint64
- Memory uint64
- KernelPath string
- Devices []VMDevices
-}
-
-type VMDevices struct {
- Path string
- ReadOnly bool
-}
-
-type VM interface {
- Create(name string, opts CreateOptions) error
- Start(name string) error
- Stop(name string) error
-}
-
-type TestVM struct {
-}
-
-func (vm *TestVM) Create(name string, opts CreateOptions) error {
- fmt.Printf("Created: %s\n", name)
- return nil
-}
-
-func (vm *TestVM) Start(name string) error {
- fmt.Printf("Started: %s\n", name)
- return nil
-}
-func (vm *TestVM) Stop(name string) error {
- fmt.Printf("Stopped: %s\n", name)
- return nil
-}
diff --git a/cmd/podman/machine/create.go b/cmd/podman/machine/create.go
index 35f0677ad..04c5e9e65 100644
--- a/cmd/podman/machine/create.go
+++ b/cmd/podman/machine/create.go
@@ -1,12 +1,11 @@
package machine
import (
- "fmt"
- "strings"
-
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/machine"
+ "github.com/containers/podman/v3/pkg/machine/qemu"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -17,17 +16,19 @@ var (
Short: "Create a vm",
Long: "Create a virtual machine for Podman to run on. Virtual machines are used to run Podman on Macs. ",
RunE: create,
- Args: cobra.ExactArgs(1),
+ Args: cobra.NoArgs,
Example: `podman machine create myvm`,
ValidArgsFunction: completion.AutocompleteNone,
}
)
type CreateCLIOptions struct {
- CPUS uint64
- Memory uint64
- KernelPath string
- Devices []string
+ CPUS uint64
+ Memory uint64
+ Devices []string
+ ImagePath string
+ IgnitionPath string
+ Name string
}
var (
@@ -45,7 +46,7 @@ func init() {
cpusFlagName := "cpus"
flags.Uint64Var(
&createOpts.CPUS,
- cpusFlagName, 0,
+ cpusFlagName, 1,
"Number of CPUs. The default is 0.000 which means no limit",
)
_ = createCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone)
@@ -53,80 +54,54 @@ func init() {
memoryFlagName := "memory"
flags.Uint64VarP(
&createOpts.Memory,
- memoryFlagName, "m", 0,
+ memoryFlagName, "m", 2048,
"Memory (in MB)",
)
_ = createCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone)
- kernelPathFlagName := "kernel-path"
+ deviceFlagName := "name"
flags.StringVar(
- &createOpts.KernelPath,
- kernelPathFlagName, "",
- "Kernel path",
- )
- _ = createCmd.RegisterFlagCompletionFunc(kernelPathFlagName, completion.AutocompleteNone)
-
- deviceFlagName := "device"
- flags.StringSliceVar(
- &createOpts.Devices,
- deviceFlagName, []string{},
- "Add a device",
+ &createOpts.Name,
+ deviceFlagName, "",
+ "set vm name",
)
_ = createCmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
+
+ ImagePathFlagName := "image-path"
+ flags.StringVar(&createOpts.ImagePath, ImagePathFlagName, "", "Path to qcow image")
+ _ = createCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault)
+
+ IgnitionPathFlagName := "ignition-path"
+ flags.StringVar(&createOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file")
+ _ = createCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault)
}
+// TODO should we allow for a users to append to the qemu cmdline?
func create(cmd *cobra.Command, args []string) error {
- vmOpts := CreateOptions{
- CPUS: createOpts.CPUS,
- Memory: createOpts.Memory,
- KernelPath: createOpts.KernelPath,
+ // TODO add ability to create default, not name required
+ if len(createOpts.Name) < 1 {
+ return errors.New("required --name not provided")
}
-
- if cmd.Flags().Changed("device") {
- devices, err := cmd.Flags().GetStringSlice("device")
- if err != nil {
- return err
- }
- vmOpts.Devices, err = parseDevices(devices)
- if err != nil {
- return err
- }
+ vmOpts := machine.CreateOptions{
+ CPUS: createOpts.CPUS,
+ Memory: createOpts.Memory,
+ IgnitionPath: createOpts.IgnitionPath,
+ ImagePath: createOpts.ImagePath,
+ Name: createOpts.Name,
}
-
- test := new(TestVM)
- test.Create(args[0], vmOpts)
-
- return nil
-}
-
-func parseDevices(devices []string) ([]VMDevices, error) {
- vmDevices := make([]VMDevices, 0, len(devices))
-
- for _, dev := range devices {
- split := strings.Split(dev, ":")
-
- if len(split) == 1 {
- vmDevices = append(vmDevices, VMDevices{
- Path: split[0],
- ReadOnly: false,
- })
- } else if len(split) == 2 {
- var readonly bool
-
- switch split[1] {
- case "ro", "readonly":
- readonly = true
- default:
- return nil, errors.New(fmt.Sprintf("Invalid readonly value: %s", dev))
- }
-
- vmDevices = append(vmDevices, VMDevices{
- Path: split[0],
- ReadOnly: readonly,
- })
- } else {
- return nil, errors.New(fmt.Sprintf("Invalid device format: %s", dev))
- }
+ var (
+ vm machine.VM
+ vmType string
+ err error
+ )
+ switch vmType {
+ case "foobar":
+ // do nothing
+ default: // qemu is the default
+ vm, err = qemu.NewMachine(vmOpts)
+ }
+ if err != nil {
+ return err
}
- return vmDevices, nil
+ return vm.Create(vmOpts)
}
diff --git a/cmd/podman/machine/destroy.go b/cmd/podman/machine/destroy.go
new file mode 100644
index 000000000..ab23d607d
--- /dev/null
+++ b/cmd/podman/machine/destroy.go
@@ -0,0 +1,91 @@
+package machine
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/machine"
+ "github.com/containers/podman/v3/pkg/machine/qemu"
+ "github.com/spf13/cobra"
+)
+
+var (
+ destroyCmd = &cobra.Command{
+ Use: "destroy [options] NAME",
+ Short: "Destroy an existing machine",
+ Long: "Destroy an existing machine ",
+ RunE: destroy,
+ Args: cobra.ExactArgs(1),
+ Example: `podman machine destroy myvm`,
+ ValidArgsFunction: completion.AutocompleteNone,
+ }
+)
+
+var (
+ destoryOptions machine.DestroyOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: destroyCmd,
+ Parent: machineCmd,
+ })
+
+ flags := destroyCmd.Flags()
+ formatFlagName := "force"
+ flags.BoolVar(&destoryOptions.Force, formatFlagName, false, "Do not prompt before destroying")
+ _ = destroyCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+
+ keysFlagName := "save-keys"
+ flags.BoolVar(&destoryOptions.SaveKeys, keysFlagName, false, "Do not delete SSH keys")
+ _ = destroyCmd.RegisterFlagCompletionFunc(keysFlagName, common.AutocompleteJSONFormat)
+
+ ignitionFlagName := "save-ignition"
+ flags.BoolVar(&destoryOptions.SaveIgnition, ignitionFlagName, false, "Do not delete ignition file")
+ _ = destroyCmd.RegisterFlagCompletionFunc(ignitionFlagName, common.AutocompleteJSONFormat)
+
+ imageFlagName := "save-image"
+ flags.BoolVar(&destoryOptions.SaveImage, imageFlagName, false, "Do not delete the image file")
+ _ = destroyCmd.RegisterFlagCompletionFunc(imageFlagName, common.AutocompleteJSONFormat)
+}
+
+func destroy(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ vm machine.VM
+ vmType string
+ )
+ switch vmType {
+ default:
+ vm, err = qemu.LoadVMByName(args[0])
+ }
+ if err != nil {
+ return err
+ }
+ confirmationMessage, doIt, err := vm.Destroy(args[0], machine.DestroyOptions{})
+ if err != nil {
+ return err
+ }
+
+ if !destoryOptions.Force {
+ // Warn user
+ fmt.Println(confirmationMessage)
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Print("Are you sure you want to continue? [y/N] ")
+ answer, err := reader.ReadString('\n')
+ if err != nil {
+ return err
+ }
+ if strings.ToLower(answer)[0] != 'y' {
+ return nil
+ }
+ }
+ return doIt()
+}
diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
new file mode 100644
index 000000000..a0656d17b
--- /dev/null
+++ b/cmd/podman/machine/ssh.go
@@ -0,0 +1,47 @@
+package machine
+
+import (
+ "github.com/containers/common/pkg/completion"
+ "github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/machine"
+ "github.com/containers/podman/v3/pkg/machine/qemu"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ sshCmd = &cobra.Command{
+ Use: "ssh NAME",
+ Short: "SSH into a virtual machine",
+ Long: "SSH into a podman-managed virtual machine ",
+ RunE: ssh,
+ Args: cobra.ExactArgs(1),
+ Example: `podman machine ssh myvm`,
+ ValidArgsFunction: completion.AutocompleteNone,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: sshCmd,
+ Parent: machineCmd,
+ })
+}
+
+func ssh(cmd *cobra.Command, args []string) error {
+ var (
+ err error
+ vm machine.VM
+ vmType string
+ )
+ switch vmType {
+ default:
+ vm, err = qemu.LoadVMByName(args[0])
+ }
+ if err != nil {
+ return errors.Wrapf(err, "vm %s not found", args[0])
+ }
+ return vm.SSH(args[0], machine.SSHOptions{})
+}
diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go
index 118ce74c0..762639358 100644
--- a/cmd/podman/machine/start.go
+++ b/cmd/podman/machine/start.go
@@ -4,6 +4,8 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/machine"
+ "github.com/containers/podman/v3/pkg/machine/qemu"
"github.com/spf13/cobra"
)
@@ -28,7 +30,17 @@ func init() {
}
func start(cmd *cobra.Command, args []string) error {
- test := new(TestVM)
- test.Start(args[0])
- return nil
+ var (
+ err error
+ vm machine.VM
+ vmType string
+ )
+ switch vmType {
+ default:
+ vm, err = qemu.LoadVMByName(args[0])
+ }
+ if err != nil {
+ return err
+ }
+ return vm.Start(args[0], machine.StartOptions{})
}
diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go
index d04b3a447..b6585c296 100644
--- a/cmd/podman/machine/stop.go
+++ b/cmd/podman/machine/stop.go
@@ -4,6 +4,8 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
+ "github.com/containers/podman/v3/pkg/machine"
+ "github.com/containers/podman/v3/pkg/machine/qemu"
"github.com/spf13/cobra"
)
@@ -27,8 +29,19 @@ func init() {
})
}
+// TODO Name shouldnt be required, need to create a default vm
func stop(cmd *cobra.Command, args []string) error {
- test := new(TestVM)
- test.Stop(args[0])
- return nil
+ var (
+ err error
+ vm machine.VM
+ vmType string
+ )
+ switch vmType {
+ default:
+ vm, err = qemu.LoadVMByName(args[0])
+ }
+ if err != nil {
+ return err
+ }
+ return vm.Stop(args[0], machine.StopOptions{})
}