diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index f3a5d65e2c..1dae8aecc1 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -26,7 +26,7 @@ var ( ValidArgsFunction: completion.AutocompleteNone, } - initOpts = machine.InitOptions{} + initOpts = define.InitOptions{} initOptionalFlags = InitOptionalFlags{} defaultMachineName = machine.DefaultMachineName now bool @@ -187,6 +187,20 @@ func initMachine(cmd *cobra.Command, args []string) error { // Finished = *, err != nil - Exit with an error message return err } + + // The following is for enabling podman machine approach + /* + s := new(p5qemu.QEMUStubber) + mc, err := p5.Init(initOpts, s) + if err != nil { + return err + } + + // TODO callback needed for the configuration file + if err := mc.Write(); err != nil { + return err + } + */ newMachineEvent(events.Init, events.Event{Name: initOpts.Name}) fmt.Println("Machine init complete") diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go index f0de62c6ae..095a78755a 100644 --- a/cmd/podman/machine/list.go +++ b/cmd/podman/machine/list.go @@ -64,6 +64,15 @@ func list(cmd *cobra.Command, args []string) error { err error ) + // Podman 5 development + /* + s := new(p5qemu.QEMUStubber) + if err := p5.List([]vmconfigs.VMStubber{s}); err != nil { + return err + } + + */ + listResponse, err = provider.List(opts) if err != nil { return fmt.Errorf("listing vms: %w", err) diff --git a/go.mod b/go.mod index b407d83100..f417f0a0b0 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/docker/go-connections v0.5.0 github.com/docker/go-plugins-helpers v0.0.0-20211224144127-6eecb7beb651 github.com/docker/go-units v0.5.0 + github.com/go-openapi/errors v0.21.0 github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 github.com/google/gofuzz v1.2.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 @@ -119,7 +120,6 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect diff --git a/pkg/machine/applehv/config.go b/pkg/machine/applehv/config.go index 26fa74665a..53454fb8bb 100644 --- a/pkg/machine/applehv/config.go +++ b/pkg/machine/applehv/config.go @@ -112,7 +112,7 @@ func (v AppleHVVirtualization) LoadVMByName(name string) (machine.VM, error) { return m.loadFromFile() } -func (v AppleHVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) { +func (v AppleHVVirtualization) NewMachine(opts define.InitOptions) (machine.VM, error) { m := MacMachine{Name: opts.Name} if len(opts.USBs) > 0 { diff --git a/pkg/machine/applehv/machine.go b/pkg/machine/applehv/machine.go index 24f420617b..b652d4f4fe 100644 --- a/pkg/machine/applehv/machine.go +++ b/pkg/machine/applehv/machine.go @@ -22,6 +22,7 @@ import ( gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/podman/v4/pkg/machine" "github.com/containers/podman/v4/pkg/machine/applehv/vfkit" + "github.com/containers/podman/v4/pkg/machine/connection" "github.com/containers/podman/v4/pkg/machine/define" "github.com/containers/podman/v4/pkg/machine/ignition" "github.com/containers/podman/v4/pkg/machine/sockets" @@ -129,7 +130,7 @@ func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket define.VMFile) // addMountsToVM converts the volumes passed through the CLI to virtio-fs mounts // and adds them to the machine -func (m *MacMachine) addMountsToVM(opts machine.InitOptions, virtiofsMnts *[]machine.VirtIoFs) error { +func (m *MacMachine) addMountsToVM(opts define.InitOptions, virtiofsMnts *[]machine.VirtIoFs) error { var mounts []vmconfigs.Mount for _, volume := range opts.Volumes { source, target, _, readOnly, err := machine.ParseVolumeFromPath(volume) @@ -145,7 +146,7 @@ func (m *MacMachine) addMountsToVM(opts machine.InitOptions, virtiofsMnts *[]mac return nil } -func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { +func (m *MacMachine) Init(opts define.InitOptions) (bool, error) { var ( key string virtiofsMnts []machine.VirtIoFs @@ -225,7 +226,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { return false, err } - err = machine.AddSSHConnectionsToPodmanSocket( + err = connection.AddSSHConnectionsToPodmanSocket( m.UID, m.Port, m.IdentityPath, @@ -294,7 +295,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) { } func (m *MacMachine) removeSystemConnections() error { - return machine.RemoveConnections(m.Name, fmt.Sprintf("%s-root", m.Name)) + return connection.RemoveConnections(m.Name, fmt.Sprintf("%s-root", m.Name)) } func (m *MacMachine) Inspect() (*machine.InspectInfo, error) { @@ -385,7 +386,7 @@ func (m *MacMachine) Remove(name string, opts machine.RemoveOptions) (string, fu confirmationMessage += "\n" return confirmationMessage, func() error { - machine.RemoveFilesAndConnections(files, m.Name, m.Name+"-root") + connection.RemoveFilesAndConnections(files, m.Name, m.Name+"-root") // TODO We will need something like this for applehv too i think /* // Remove the HVSOCK for networking diff --git a/pkg/machine/config.go b/pkg/machine/config.go index f0198c9305..e498b75c00 100644 --- a/pkg/machine/config.go +++ b/pkg/machine/config.go @@ -22,36 +22,14 @@ import ( "github.com/sirupsen/logrus" ) -type InitOptions struct { - CPUS uint64 - DiskSize uint64 - IgnitionPath string - ImagePath string - Volumes []string - VolumeDriver string - IsDefault bool - Memory uint64 - Name string - TimeZone string - URI url.URL - Username string - ReExec bool - Rootful bool - UID string // uid of the user that called machine - UserModeNetworking *bool // nil = use backend/system default, false = disable, true = enable - USBs []string -} - const ( DefaultMachineName string = "podman-machine-default" apiUpTimeout = 20 * time.Second ) -type RemoteConnectionType string - var ( - SSHRemoteConnection RemoteConnectionType = "ssh" - ForwarderBinaryName = "gvproxy" + DefaultIgnitionUserName = "core" + ForwarderBinaryName = "gvproxy" ) type Download struct { @@ -120,7 +98,7 @@ type RemoveOptions struct { type InspectOptions struct{} type VM interface { - Init(opts InitOptions) (bool, error) + Init(opts define.InitOptions) (bool, error) Inspect() (*InspectInfo, error) Remove(name string, opts RemoveOptions) (string, func() error, error) Set(name string, opts SetOptions) ([]error, error) @@ -130,24 +108,6 @@ type VM interface { Stop(name string, opts StopOptions) error } -func GetLock(name string, vmtype define.VMType) (*lockfile.LockFile, error) { - // FIXME: there's a painful amount of `GetConfDir` calls scattered - // across the code base. This should be done once and stored - // somewhere instead. - vmConfigDir, err := GetConfDir(vmtype) - if err != nil { - return nil, err - } - - lockPath := filepath.Join(vmConfigDir, name+".lock") - lock, err := lockfile.GetLockFile(lockPath) - if err != nil { - return nil, fmt.Errorf("creating lockfile for VM: %w", err) - } - - return lock, nil -} - type DistributionDownload interface { HasUsableCache() (bool, error) Get() *Download @@ -167,26 +127,6 @@ type InspectInfo struct { Rootful bool } -func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL { - // TODO Should this function have input verification? - userInfo := url.User(userName) - uri := url.URL{ - Scheme: "ssh", - Opaque: "", - User: userInfo, - Host: host, - Path: path, - RawPath: "", - ForceQuery: false, - RawQuery: "", - Fragment: "", - } - if len(port) > 0 { - uri.Host = net.JoinHostPort(uri.Hostname(), port) - } - return uri -} - // GetCacheDir returns the dir where VM images are downloaded into when pulled func GetCacheDir(vmType define.VMType) (string, error) { dataDir, err := GetDataDir(vmType) @@ -226,6 +166,26 @@ func GetGlobalDataDir() (string, error) { return dataDir, os.MkdirAll(dataDir, 0755) } +func GetMachineDirs(vmType define.VMType) (*define.MachineDirs, error) { + rtDir, err := getRuntimeDir() + if err != nil { + return nil, err + } + + rtDir = filepath.Join(rtDir, "podman") + configDir, err := GetConfDir(vmType) + if err != nil { + return nil, err + } + dataDir, err := GetDataDir(vmType) + dirs := define.MachineDirs{ + ConfigDir: configDir, + DataDir: dataDir, + RuntimeDir: rtDir, + } + return &dirs, err +} + // DataDirPrefix returns the path prefix for all machine data files func DataDirPrefix() (string, error) { data, err := homedir.GetDataHome() @@ -307,7 +267,7 @@ type VirtProvider interface { //nolint:interfacebloat IsValidVMName(name string) (bool, error) List(opts ListOptions) ([]*ListResponse, error) LoadVMByName(name string) (VM, error) - NewMachine(opts InitOptions) (VM, error) + NewMachine(opts define.InitOptions) (VM, error) NewDownload(vmName string) (Download, error) RemoveAndCleanMachines() error VMType() define.VMType @@ -465,3 +425,22 @@ func (dl Download) AcquireVMImage(imagePath string) (*define.VMFile, FCOSStream, } return imageLocation, fcosStream, nil } + +// Deprecated: GetLock +func GetLock(name string, vmtype define.VMType) (*lockfile.LockFile, error) { + // FIXME: there's a painful amount of `GetConfDir` calls scattered + // across the code base. This should be done once and stored + // somewhere instead. + vmConfigDir, err := GetConfDir(vmtype) + if err != nil { + return nil, err + } + + lockPath := filepath.Join(vmConfigDir, name+".lock") + lock, err := lockfile.GetLockFile(lockPath) + if err != nil { + return nil, fmt.Errorf("creating lockfile for VM: %w", err) + } + + return lock, nil +} diff --git a/pkg/machine/config_test.go b/pkg/machine/config_test.go index 1ffbbc9ce4..dc91d32125 100644 --- a/pkg/machine/config_test.go +++ b/pkg/machine/config_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/containers/podman/v4/pkg/machine/connection" ) func TestRemoteConnectionType_MakeSSHURL(t *testing.T) { @@ -27,7 +28,7 @@ func TestRemoteConnectionType_MakeSSHURL(t *testing.T) { } tests := []struct { name string - rc RemoteConnectionType + rc connection.RemoteConnectionType args args want url.URL }{ diff --git a/pkg/machine/connection/add.go b/pkg/machine/connection/add.go new file mode 100644 index 0000000000..c69d6751d3 --- /dev/null +++ b/pkg/machine/connection/add.go @@ -0,0 +1,36 @@ +package connection + +import ( + "fmt" + "net/url" + "strconv" + + "github.com/containers/podman/v4/pkg/machine/define" +) + +// AddSSHConnectionsToPodmanSocket adds SSH connections to the podman socket if +// no ignition path is provided +func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUsername string, opts define.InitOptions) error { + if len(opts.IgnitionPath) > 0 { + fmt.Println("An ignition path was provided. No SSH connection was added to Podman") + return nil + } + uri := SSHRemoteConnection.MakeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername) + uriRoot := SSHRemoteConnection.MakeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root") + + uris := []url.URL{uri, uriRoot} + names := []string{name, name + "-root"} + + // The first connection defined when connections is empty will become the default + // regardless of IsDefault, so order according to rootful + if opts.Rootful { + uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0] + } + + for i := 0; i < 2; i++ { + if err := AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil { + return err + } + } + return nil +} diff --git a/pkg/machine/connection.go b/pkg/machine/connection/connection.go similarity index 82% rename from pkg/machine/connection.go rename to pkg/machine/connection/connection.go index c34ba4816f..11f2ba7b18 100644 --- a/pkg/machine/connection.go +++ b/pkg/machine/connection/connection.go @@ -1,10 +1,12 @@ //go:build amd64 || arm64 -package machine +package connection import ( "errors" "fmt" + "net" + "net/url" "os" "github.com/containers/common/pkg/config" @@ -105,3 +107,28 @@ func RemoveFilesAndConnections(files []string, names ...string) { logrus.Error(err) } } + +type RemoteConnectionType string + +var SSHRemoteConnection RemoteConnectionType = "ssh" + +// MakeSSHURL +func (rc RemoteConnectionType) MakeSSHURL(host, path, port, userName string) url.URL { + // TODO Should this function have input verification? + userInfo := url.User(userName) + uri := url.URL{ + Scheme: "ssh", + Opaque: "", + User: userInfo, + Host: host, + Path: path, + RawPath: "", + ForceQuery: false, + RawQuery: "", + Fragment: "", + } + if len(port) > 0 { + uri.Host = net.JoinHostPort(uri.Hostname(), port) + } + return uri +} diff --git a/pkg/machine/define/config.go b/pkg/machine/define/config.go index f7a8bbd48d..2c3224d7d2 100644 --- a/pkg/machine/define/config.go +++ b/pkg/machine/define/config.go @@ -1,4 +1,21 @@ package define +import "os" + const UserCertsTargetPath = "/etc/containers/certs.d" const DefaultIdentityName = "machine" + +var ( + DefaultFilePerm os.FileMode = 0644 +) + +type CreateVMOpts struct { + Name string + Dirs *MachineDirs +} + +type MachineDirs struct { + ConfigDir string + DataDir string + RuntimeDir string +} diff --git a/pkg/machine/define/initopts.go b/pkg/machine/define/initopts.go new file mode 100644 index 0000000000..06bbef8520 --- /dev/null +++ b/pkg/machine/define/initopts.go @@ -0,0 +1,23 @@ +package define + +import "net/url" + +type InitOptions struct { + CPUS uint64 + DiskSize uint64 + IgnitionPath string + ImagePath string + Volumes []string + VolumeDriver string + IsDefault bool + Memory uint64 + Name string + TimeZone string + URI url.URL + Username string + ReExec bool + Rootful bool + UID string // uid of the user that called machine + UserModeNetworking *bool // nil = use backend/system default, false = disable, true = enable + USBs []string +} diff --git a/pkg/machine/hyperv/config.go b/pkg/machine/hyperv/config.go index fe09d46ca5..39264d97fb 100644 --- a/pkg/machine/hyperv/config.go +++ b/pkg/machine/hyperv/config.go @@ -116,7 +116,7 @@ func (v HyperVVirtualization) LoadVMByName(name string) (machine.VM, error) { return m.loadFromFile() } -func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) { +func (v HyperVVirtualization) NewMachine(opts define.InitOptions) (machine.VM, error) { m := HyperVMachine{Name: opts.Name} if len(opts.ImagePath) < 1 { return nil, errors.New("must define --image-path for hyperv support") diff --git a/pkg/machine/hyperv/machine.go b/pkg/machine/hyperv/machine.go index 6c0982eb4d..e95ebb303a 100644 --- a/pkg/machine/hyperv/machine.go +++ b/pkg/machine/hyperv/machine.go @@ -20,6 +20,7 @@ import ( gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/libhvee/pkg/hypervctl" "github.com/containers/podman/v4/pkg/machine" + "github.com/containers/podman/v4/pkg/machine/connection" "github.com/containers/podman/v4/pkg/machine/define" "github.com/containers/podman/v4/pkg/machine/hyperv/vsock" "github.com/containers/podman/v4/pkg/machine/ignition" @@ -129,7 +130,7 @@ func (m *HyperVMachine) readAndSplitIgnition() error { return vm.SplitAndAddIgnition("ignition.config.", reader) } -func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) { +func (m *HyperVMachine) Init(opts define.InitOptions) (bool, error) { var ( key string err error @@ -192,7 +193,7 @@ func (m *HyperVMachine) Init(opts machine.InitOptions) (bool, error) { m.Port = sshPort m.RemoteUsername = opts.Username - err = machine.AddSSHConnectionsToPodmanSocket( + err = connection.AddSSHConnectionsToPodmanSocket( m.UID, m.Port, m.IdentityPath, @@ -315,7 +316,7 @@ func (m *HyperVMachine) unregisterMachine() error { } func (m *HyperVMachine) removeSystemConnections() error { - return machine.RemoveConnections(m.Name, fmt.Sprintf("%s-root", m.Name)) + return connection.RemoveConnections(m.Name, fmt.Sprintf("%s-root", m.Name)) } func (m *HyperVMachine) Inspect() (*machine.InspectInfo, error) { @@ -441,7 +442,7 @@ func (m *HyperVMachine) Remove(_ string, opts machine.RemoveOptions) (string, fu confirmationMessage += "\n" return confirmationMessage, func() error { - machine.RemoveFilesAndConnections(files, m.Name, m.Name+"-root") + connection.RemoveFilesAndConnections(files, m.Name, m.Name+"-root") m.removeNetworkAndReadySocketsFromRegistry() if err := vm.Remove(""); err != nil { return fmt.Errorf("removing virtual machine: %w", err) diff --git a/pkg/machine/lock/lock.go b/pkg/machine/lock/lock.go new file mode 100644 index 0000000000..ede7075c9f --- /dev/null +++ b/pkg/machine/lock/lock.go @@ -0,0 +1,17 @@ +package lock + +import ( + "fmt" + "path/filepath" + + "github.com/containers/storage/pkg/lockfile" +) + +func GetMachineLock(name string, machineConfigDir string) (*lockfile.LockFile, error) { + lockPath := filepath.Join(machineConfigDir, name+".lock") + lock, err := lockfile.GetLockFile(lockPath) + if err != nil { + return nil, fmt.Errorf("creating lockfile for VM: %w", err) + } + return lock, nil +} diff --git a/pkg/machine/machine_common.go b/pkg/machine/machine_common.go index 5d440c6681..eb497ece12 100644 --- a/pkg/machine/machine_common.go +++ b/pkg/machine/machine_common.go @@ -5,10 +5,9 @@ package machine import ( "encoding/json" "fmt" - "net/url" "os" - "strconv" + "github.com/containers/podman/v4/pkg/machine/connection" "github.com/containers/storage/pkg/ioutils" ) @@ -30,33 +29,6 @@ func GetDevNullFiles() (*os.File, *os.File, error) { return dnr, dnw, nil } -// AddSSHConnectionsToPodmanSocket adds SSH connections to the podman socket if -// no ignition path is provided -func AddSSHConnectionsToPodmanSocket(uid, port int, identityPath, name, remoteUsername string, opts InitOptions) error { - if len(opts.IgnitionPath) > 0 { - fmt.Println("An ignition path was provided. No SSH connection was added to Podman") - return nil - } - uri := SSHRemoteConnection.MakeSSHURL(LocalhostIP, fmt.Sprintf("/run/user/%d/podman/podman.sock", uid), strconv.Itoa(port), remoteUsername) - uriRoot := SSHRemoteConnection.MakeSSHURL(LocalhostIP, "/run/podman/podman.sock", strconv.Itoa(port), "root") - - uris := []url.URL{uri, uriRoot} - names := []string{name, name + "-root"} - - // The first connection defined when connections is empty will become the default - // regardless of IsDefault, so order according to rootful - if opts.Rootful { - uris[0], names[0], uris[1], names[1] = uris[1], names[1], uris[0], names[0] - } - - for i := 0; i < 2; i++ { - if err := AddConnection(&uris[i], names[i], identityPath, opts.IsDefault && i == 0); err != nil { - return err - } - } - return nil -} - // WaitAPIAndPrintInfo prints info about the machine and does a ping test on the // API socket func WaitAPIAndPrintInfo(forwardState APIForwardingState, name, helper, forwardSock string, noInfo, isIncompatible, rootful bool) { @@ -158,7 +130,7 @@ following command in your terminal session: // SetRootful modifies the machine's default connection to be either rootful or // rootless func SetRootful(rootful bool, name, rootfulName string) error { - return UpdateConnectionIfDefault(rootful, name, rootfulName) + return connection.UpdateConnectionIfDefault(rootful, name, rootfulName) } // WriteConfig writes the machine's JSON config file diff --git a/pkg/machine/options_darwin.go b/pkg/machine/options_darwin.go new file mode 100644 index 0000000000..3959175d2c --- /dev/null +++ b/pkg/machine/options_darwin.go @@ -0,0 +1,11 @@ +package machine + +import "os" + +func getRuntimeDir() (string, error) { + tmpDir, ok := os.LookupEnv("TMPDIR") + if !ok { + tmpDir = "/tmp" + } + return tmpDir, nil +} diff --git a/pkg/machine/options_freebsd.go b/pkg/machine/options_freebsd.go new file mode 100644 index 0000000000..3959175d2c --- /dev/null +++ b/pkg/machine/options_freebsd.go @@ -0,0 +1,11 @@ +package machine + +import "os" + +func getRuntimeDir() (string, error) { + tmpDir, ok := os.LookupEnv("TMPDIR") + if !ok { + tmpDir = "/tmp" + } + return tmpDir, nil +} diff --git a/pkg/machine/options_linux.go b/pkg/machine/options_linux.go new file mode 100644 index 0000000000..9f629e1c6f --- /dev/null +++ b/pkg/machine/options_linux.go @@ -0,0 +1,13 @@ +package machine + +import ( + "github.com/containers/podman/v4/pkg/rootless" + "github.com/containers/podman/v4/pkg/util" +) + +func getRuntimeDir() (string, error) { + if !rootless.IsRootless() { + return "/run", nil + } + return util.GetRootlessRuntimeDir() +} diff --git a/pkg/machine/options_windows.go b/pkg/machine/options_windows.go new file mode 100644 index 0000000000..1a880069c6 --- /dev/null +++ b/pkg/machine/options_windows.go @@ -0,0 +1,11 @@ +package machine + +import "os" + +func getRuntimeDir() (string, error) { + tmpDir, ok := os.LookupEnv("TEMP") + if !ok { + tmpDir = os.Getenv("LOCALAPPDATA") + "\\Temp" + } + return tmpDir, nil +} diff --git a/pkg/machine/p5/host.go b/pkg/machine/p5/host.go new file mode 100644 index 0000000000..78dd64663e --- /dev/null +++ b/pkg/machine/p5/host.go @@ -0,0 +1,134 @@ +package p5 + +import ( + "context" + "encoding/json" + "fmt" + "maps" + + "github.com/containers/podman/v4/pkg/machine" + machineDefine "github.com/containers/podman/v4/pkg/machine/define" + "github.com/containers/podman/v4/pkg/machine/ocipull" + "github.com/containers/podman/v4/pkg/machine/vmconfigs" + "github.com/sirupsen/logrus" +) + +/* +Host + ├ Info + ├ OS Apply + ├ SSH + ├ List + ├ Init + ├ VMExists + ├ CheckExclusiveActiveVM *HyperV/WSL need to check their hypervisors as well +*/ + +func Info() {} +func OSApply() {} +func SSH() {} + +// List is done at the host level to allow for a *possible* future where +// more than one provider is used +func List(vmstubbers []vmconfigs.VMStubber) error { + mcs, err := getMCs(vmstubbers) + if err != nil { + return err + } + + fmt.Println("machines") + for name, mc := range mcs { + logrus.Debugf("found machine -> %q %q", name, mc.Created) + } + fmt.Println("machines end") + + return nil +} + +func Init(opts machineDefine.InitOptions, mp vmconfigs.VMStubber) (*vmconfigs.MachineConfig, error) { + dirs, err := machine.GetMachineDirs(mp.VMType()) + if err != nil { + return nil, err + } + fmt.Println("/// begin init") + + mc, err := vmconfigs.NewMachineConfig(opts, dirs.ConfigDir) + if err != nil { + return nil, err + } + createOpts := machineDefine.CreateVMOpts{ + Name: opts.Name, + Dirs: dirs, + } + + // Get Image + // TODO This needs rework bigtime; my preference is most of below of not living in here. + versionedOCIDownload, err := ocipull.NewVersioned(context.Background(), dirs.DataDir, opts.Name, mp.VMType().String()) + if err != nil { + return nil, err + } + + if err := versionedOCIDownload.Pull(); err != nil { + return nil, err + } + unpacked, err := versionedOCIDownload.Unpack() + if err != nil { + return nil, err + } + defer func() { + logrus.Debugf("cleaning up %q", unpacked.GetPath()) + if err := unpacked.Delete(); err != nil { + logrus.Errorf("unable to delete local compressed file %q:%v", unpacked.GetPath(), err) + } + }() + imagePath, err := versionedOCIDownload.Decompress(unpacked) + if err != nil { + return nil, err + } + + mc.ImagePath = imagePath + + // TODO needs callback to remove image + + logrus.Debugf("--> imagePath is %q", imagePath.GetPath()) + // TODO development only -- set to qemu provider + if err := mp.CreateVM(createOpts, mc); err != nil { + return nil, err + } + + b, err := json.MarshalIndent(mc, "", " ") + if err != nil { + return nil, err + } + fmt.Println(string(b)) + fmt.Println("/// end init") + return mc, nil +} + +// VMExists looks across given providers for a machine's existence. returns the actual config and found bool +func VMExists(name string, vmstubbers []vmconfigs.VMStubber) (*vmconfigs.MachineConfig, bool, error) { + mcs, err := getMCs(vmstubbers) + if err != nil { + return nil, false, err + } + mc, found := mcs[name] + return mc, found, nil +} + +func CheckExclusiveActiveVM() {} + +func getMCs(vmstubbers []vmconfigs.VMStubber) (map[string]*vmconfigs.MachineConfig, error) { + mcs := make(map[string]*vmconfigs.MachineConfig) + for _, stubber := range vmstubbers { + dirs, err := machine.GetMachineDirs(stubber.VMType()) + if err != nil { + return nil, err + } + stubberMCs, err := vmconfigs.LoadMachinesInDir(dirs.ConfigDir) + if err != nil { + return nil, err + } + maps.Copy(mcs, stubberMCs) + } + return mcs, nil +} diff --git a/pkg/machine/qemu/command/command.go b/pkg/machine/qemu/command/command.go index 3619619ef3..02f1a59d43 100644 --- a/pkg/machine/qemu/command/command.go +++ b/pkg/machine/qemu/command/command.go @@ -2,7 +2,9 @@ package command import ( "encoding/base64" + "errors" "fmt" + "io/fs" "os" "path/filepath" "strconv" @@ -14,6 +16,12 @@ import ( "github.com/containers/podman/v4/pkg/machine/define" ) +// defaultQMPTimeout is the timeout duration for the +// qmp monitor interactions. +var ( + defaultQMPTimeout = 2 * time.Second +) + // QemuCmd is an alias around a string slice to prevent the need to migrate the // MachineVM struct due to changes type QemuCmd []string @@ -234,3 +242,22 @@ type Monitor struct { // Timeout in seconds for qmp monitor transactions Timeout time.Duration } + +// NewQMPMonitor creates the monitor subsection of our vm +func NewQMPMonitor(name, machineRuntimeDir string) (Monitor, error) { + if _, err := os.Stat(machineRuntimeDir); errors.Is(err, fs.ErrNotExist) { + if err := os.MkdirAll(machineRuntimeDir, 0755); err != nil { + return Monitor{}, err + } + } + address, err := define.NewMachineFile(filepath.Join(machineRuntimeDir, "qmp_"+name+".sock"), nil) + if err != nil { + return Monitor{}, err + } + monitor := Monitor{ + Network: "unix", + Address: *address, + Timeout: defaultQMPTimeout, + } + return monitor, nil +} diff --git a/pkg/machine/qemu/config.go b/pkg/machine/qemu/config.go index e15e7b0387..358e751390 100644 --- a/pkg/machine/qemu/config.go +++ b/pkg/machine/qemu/config.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/containers/podman/v4/pkg/machine/vmconfigs" + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/pkg/machine" "github.com/containers/podman/v4/pkg/machine/compression" @@ -16,7 +18,6 @@ import ( "github.com/containers/podman/v4/pkg/machine/ignition" "github.com/containers/podman/v4/pkg/machine/qemu/command" "github.com/containers/podman/v4/pkg/machine/sockets" - "github.com/containers/podman/v4/pkg/machine/vmconfigs" "github.com/containers/podman/v4/utils" "github.com/docker/go-units" "github.com/sirupsen/logrus" @@ -51,7 +52,7 @@ func findQEMUBinary() (string, error) { // setQMPMonitorSocket sets the virtual machine's QMP Monitor socket func (v *MachineVM) setQMPMonitorSocket() error { - monitor, err := NewQMPMonitor("unix", v.Name, defaultQMPTimeout) + monitor, err := newQMPMonitor("unix", v.Name, defaultQMPTimeout) if err != nil { return err } @@ -74,7 +75,7 @@ func (v *MachineVM) setNewMachineCMD(qemuBinary string, cmdOpts *setNewMachineCM // NewMachine initializes an instance of a virtual machine based on the qemu // virtualization. -func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) { +func (p *QEMUVirtualization) NewMachine(opts define.InitOptions) (machine.VM, error) { vm := new(MachineVM) if len(opts.Name) > 0 { vm.Name = opts.Name @@ -159,7 +160,7 @@ func (p *QEMUVirtualization) LoadVMByName(name string) (machine.VM, error) { return nil, err } - lock, err := machine.GetLock(vm.Name, vmtype) + lock, err := machine.GetLock(vm.Name, vmtype) //nolint:staticcheck if err != nil { return nil, err } diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go index 93de8b5609..2608a7a8c4 100644 --- a/pkg/machine/qemu/machine.go +++ b/pkg/machine/qemu/machine.go @@ -22,6 +22,7 @@ import ( "github.com/containers/common/pkg/config" gvproxy "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/podman/v4/pkg/machine" + "github.com/containers/podman/v4/pkg/machine/connection" "github.com/containers/podman/v4/pkg/machine/define" "github.com/containers/podman/v4/pkg/machine/ignition" "github.com/containers/podman/v4/pkg/machine/qemu/command" @@ -84,7 +85,7 @@ type MachineVM struct { // addMountsToVM converts the volumes passed through the CLI into the specified // volume driver and adds them to the machine -func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error { +func (v *MachineVM) addMountsToVM(opts define.InitOptions) error { var volumeType string switch opts.VolumeDriver { // "" is the default volume driver @@ -112,7 +113,7 @@ func (v *MachineVM) addMountsToVM(opts machine.InitOptions) error { // Init writes the json configuration file to the filesystem for // other verbs (start, stop) -func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { +func (v *MachineVM) Init(opts define.InitOptions) (bool, error) { var ( key string err error @@ -150,7 +151,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { // Add location of bootable image v.CmdLine.SetBootableImage(v.getImageFile()) - if err = machine.AddSSHConnectionsToPodmanSocket( + if err = connection.AddSSHConnectionsToPodmanSocket( v.UID, v.Port, v.IdentityPath, @@ -234,7 +235,7 @@ func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { } func (v *MachineVM) removeSystemConnections() error { - return machine.RemoveConnections(v.Name, fmt.Sprintf("%s-root", v.Name)) + return connection.RemoveConnections(v.Name, fmt.Sprintf("%s-root", v.Name)) } func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) { @@ -877,8 +878,8 @@ func (v *MachineVM) stopLocked() error { return nil } -// NewQMPMonitor creates the monitor subsection of our vm -func NewQMPMonitor(network, name string, timeout time.Duration) (command.Monitor, error) { +// Deprecated: newQMPMonitor creates the monitor subsection of our vm +func newQMPMonitor(network, name string, timeout time.Duration) (command.Monitor, error) { rtDir, err := getRuntimeDir() if err != nil { return command.Monitor{}, err @@ -991,7 +992,7 @@ func (v *MachineVM) Remove(_ string, opts machine.RemoveOptions) (string, func() confirmationMessage += "\n" return confirmationMessage, func() error { - machine.RemoveFilesAndConnections(files, v.Name, v.Name+"-root") + connection.RemoveFilesAndConnections(files, v.Name, v.Name+"-root") return nil }, nil } diff --git a/pkg/machine/qemu/p5qemu/stubber.go b/pkg/machine/qemu/p5qemu/stubber.go new file mode 100644 index 0000000000..b357063911 --- /dev/null +++ b/pkg/machine/qemu/p5qemu/stubber.go @@ -0,0 +1,69 @@ +package p5qemu + +import ( + "fmt" + + "github.com/containers/podman/v4/pkg/machine/define" + "github.com/containers/podman/v4/pkg/machine/qemu/command" + "github.com/containers/podman/v4/pkg/machine/vmconfigs" + "github.com/go-openapi/errors" +) + +type QEMUStubber struct { + vmconfigs.QEMUConfig +} + +func (q *QEMUStubber) CreateVM(opts define.CreateVMOpts, mc *vmconfigs.MachineConfig) error { + fmt.Println("//// CreateVM: ", opts.Name) + monitor, err := command.NewQMPMonitor(opts.Name, opts.Dirs.RuntimeDir) + if err != nil { + return err + } + qemuConfig := vmconfigs.QEMUConfig{ + Command: nil, + QMPMonitor: monitor, + } + + mc.QEMUHypervisor = &qemuConfig + return nil +} + +func (q *QEMUStubber) StartVM() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) StopVM() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) InspectVM() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) RemoveVM() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) ChangeSettings() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) IsFirstBoot() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) SetupMounts() error { + return errors.NotImplemented("") +} + +func (q *QEMUStubber) CheckExclusiveActiveVM() (bool, string, error) { + return false, "", errors.NotImplemented("") +} + +func (q *QEMUStubber) GetHyperVisorVMs() ([]string, error) { + return nil, nil +} + +func (q *QEMUStubber) VMType() define.VMType { + return define.QemuVirt +} diff --git a/pkg/machine/qemuprovider.go b/pkg/machine/qemuprovider.go new file mode 100644 index 0000000000..50473223f8 --- /dev/null +++ b/pkg/machine/qemuprovider.go @@ -0,0 +1 @@ +package machine diff --git a/pkg/machine/vmconfigs/config.go b/pkg/machine/vmconfigs/config.go index 8a4cb1e718..0ca4f4d923 100644 --- a/pkg/machine/vmconfigs/config.go +++ b/pkg/machine/vmconfigs/config.go @@ -11,8 +11,6 @@ import ( "github.com/containers/storage/pkg/lockfile" ) -type aThing struct{} - type MachineConfig struct { // Common stuff Created time.Time @@ -32,6 +30,8 @@ type MachineConfig struct { // Image stuff imageDescription machineImage //nolint:unused + ImagePath *define.VMFile // Temporary only until a proper image struct is worked out + // Provider stuff AppleHypervisor *AppleHVConfig `json:",omitempty"` QEMUHypervisor *QEMUConfig `json:",omitempty"` @@ -39,11 +39,14 @@ type MachineConfig struct { WSLHypervisor *WSLConfig `json:",omitempty"` lock *lockfile.LockFile //nolint:unused + + // configPath can be used for reading, writing, removing + configPath *define.VMFile } // MachineImage describes a podman machine image type MachineImage struct { - OCI *ociMachineImage + OCI *OCIMachineImage FCOS *fcosMachineImage } @@ -63,7 +66,7 @@ type machineImage interface { //nolint:unused path() string } -type ociMachineImage struct { +type OCIMachineImage struct { // registry // TODO JSON serial/deserial will write string to disk // but in code it is a types.ImageReference @@ -72,11 +75,11 @@ type ociMachineImage struct { FQImageReference string } -func (o ociMachineImage) path() string { +func (o OCIMachineImage) path() string { return "" } -func (o ociMachineImage) download() error { +func (o OCIMachineImage) download() error { return nil } @@ -94,6 +97,13 @@ func (f fcosMachineImage) path() string { return "" } +type VMStubber interface { + CreateVM(opts define.CreateVMOpts, mc *MachineConfig) error + VMType() define.VMType + GetHyperVisorVMs() ([]string, error) +} +type aThing struct{} + // HostUser describes the host user type HostUser struct { // Whether this machine should run in a rootful or rootless manner diff --git a/pkg/machine/vmconfigs/config_darwin.go b/pkg/machine/vmconfigs/config_darwin.go index 62bdff414e..4f326988f6 100644 --- a/pkg/machine/vmconfigs/config_darwin.go +++ b/pkg/machine/vmconfigs/config_darwin.go @@ -1,6 +1,8 @@ package vmconfigs import ( + "os" + "github.com/containers/podman/v4/pkg/machine/applehv/vfkit" ) @@ -13,3 +15,7 @@ type AppleHVConfig struct { type HyperVConfig struct{} type WSLConfig struct{} type QEMUConfig struct{} + +func getHostUID() int { + return os.Getuid() +} diff --git a/pkg/machine/vmconfigs/config_freebsd.go b/pkg/machine/vmconfigs/config_freebsd.go index 1970769ff4..f5f17512af 100644 --- a/pkg/machine/vmconfigs/config_freebsd.go +++ b/pkg/machine/vmconfigs/config_freebsd.go @@ -1,7 +1,13 @@ package vmconfigs +import "os" + // Stubs type HyperVConfig struct{} -type WSLConfig struct {} -type QEMUConfig struct {} -type AppleHVConfig struct {} +type WSLConfig struct{} +type QEMUConfig struct{} +type AppleHVConfig struct{} + +func getHostUID() int { + return os.Getuid() +} diff --git a/pkg/machine/vmconfigs/config_linux.go b/pkg/machine/vmconfigs/config_linux.go index 59d37e8f44..9604ffc790 100644 --- a/pkg/machine/vmconfigs/config_linux.go +++ b/pkg/machine/vmconfigs/config_linux.go @@ -1,14 +1,22 @@ package vmconfigs import ( + "os" + "github.com/containers/podman/v4/pkg/machine/qemu/command" ) type QEMUConfig struct { - cmd command.QemuCmd //nolint:unused + Command command.QemuCmd + // QMPMonitor is the qemu monitor object for sending commands + QMPMonitor command.Monitor } // Stubs type AppleHVConfig struct{} type HyperVConfig struct{} type WSLConfig struct{} + +func getHostUID() int { + return os.Getuid() +} diff --git a/pkg/machine/vmconfigs/config_windows.go b/pkg/machine/vmconfigs/config_windows.go index 8cec6976ea..e4f47dc348 100644 --- a/pkg/machine/vmconfigs/config_windows.go +++ b/pkg/machine/vmconfigs/config_windows.go @@ -19,3 +19,7 @@ type WSLConfig struct { // Stubs type QEMUConfig struct{} type AppleHVConfig struct{} + +func getHostUID() int { + return 1000 +} diff --git a/pkg/machine/vmconfigs/machine.go b/pkg/machine/vmconfigs/machine.go new file mode 100644 index 0000000000..486ef61008 --- /dev/null +++ b/pkg/machine/vmconfigs/machine.go @@ -0,0 +1,200 @@ +package vmconfigs + +import ( + "encoding/json" + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + "time" + + "github.com/sirupsen/logrus" + + define2 "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/machine/define" + "github.com/containers/podman/v4/pkg/machine/lock" + "github.com/containers/podman/v4/utils" +) + +/* + info Display machine host info common + init Initialize a virtual machine specific + inspect Inspect an existing machine specific + list List machines specific + os Manage a Podman virtual machine's OS common + rm Remove an existing machine specific + set Set a virtual machine setting specific + ssh SSH into an existing machine common + start Start an existing machine specific + stop Stop an existing machine specific +*/ + +var ( + SSHRemoteConnection RemoteConnectionType = "ssh" + DefaultIgnitionUserName = "core" + ForwarderBinaryName = "gvproxy" +) + +type RemoteConnectionType string + +// NewMachineConfig creates the initial machine configuration file from cli options +func NewMachineConfig(opts define.InitOptions, machineConfigDir string) (*MachineConfig, error) { + mc := new(MachineConfig) + mc.Name = opts.Name + + machineLock, err := lock.GetMachineLock(opts.Name, machineConfigDir) + if err != nil { + return nil, err + } + mc.lock = machineLock + + cf, err := define.NewMachineFile(filepath.Join(machineConfigDir, fmt.Sprintf("%s.json", opts.Name)), nil) + if err != nil { + return nil, err + } + mc.configPath = cf + + // System Resources + mrc := ResourceConfig{ + CPUs: opts.CPUS, + DiskSize: opts.DiskSize, + Memory: opts.Memory, + USBs: nil, // Needs to be filled in by providers? + } + mc.Resources = mrc + + sshPort, err := utils.GetRandomPort() + if err != nil { + return nil, err + } + + // Single key examination should occur here + sshConfig := SSHConfig{ + IdentityPath: "/home/baude/.local/share/containers/podman/machine", // TODO Fix this + Port: sshPort, + RemoteUsername: opts.Username, + } + + mc.SSH = sshConfig + mc.Created = time.Now() + + mc.HostUser = HostUser{UID: getHostUID(), Rootful: opts.Rootful} + + // TODO - Temporarily disabled to make things easier + /* + // TODO AddSSHConnectionToPodmanSocket could put converted become a method of MachineConfig + if err := connection.AddSSHConnectionsToPodmanSocket(mc.HostUser.UID, mc.SSH.Port, mc.SSH.IdentityPath, mc.Name, mc.SSH.RemoteUsername, opts); err != nil { + return nil, err + } + */ + // addcallback for ssh connections here + + return mc, nil +} + +// Lock creates a lock on the machine for single access +func (mc *MachineConfig) Lock() { + mc.lock.Lock() +} + +// Unlock removes an existing lock +func (mc *MachineConfig) Unlock() { + mc.lock.Unlock() +} + +// Write is a locking way to the machine configuration file +func (mc *MachineConfig) Write() error { + mc.Lock() + defer mc.Unlock() + return mc.write() +} + +// write is a non-locking way to write the machine configuration file to disk +func (mc *MachineConfig) write() error { + if mc.configPath == nil { + return fmt.Errorf("no configuration file associated with vm %q", mc.Name) + } + b, err := json.Marshal(mc) + if err != nil { + return err + } + logrus.Debugf("writing configuration file %q", mc.configPath.Path) + return os.WriteFile(mc.configPath.GetPath(), b, define.DefaultFilePerm) +} + +func (mc *MachineConfig) removeSystemConnection() error { //nolint:unused + return define2.ErrNotImplemented +} + +// updateLastBoot writes the current time to the machine configuration file. it is +// an non-locking method and assumes it is being called locked +func (mc *MachineConfig) updateLastBoot() error { //nolint:unused + mc.LastUp = time.Now() + return mc.Write() +} + +func (mc *MachineConfig) removeMachineFiles() error { //nolint:unused + return define2.ErrNotImplemented +} + +func (mc *MachineConfig) Info() error { // signature TBD + return define2.ErrNotImplemented +} + +func (mc *MachineConfig) OSApply() error { // signature TBD + return define2.ErrNotImplemented +} + +func (mc *MachineConfig) SecureShell() error { // Used SecureShell instead of SSH to do struct collision + return define2.ErrNotImplemented +} + +func (mc *MachineConfig) Inspect() error { // signature TBD + return define2.ErrNotImplemented +} + +func (mc *MachineConfig) ConfigDir() (string, error) { + if mc.configPath == nil { + return "", errors.New("no configuration directory set") + } + return filepath.Dir(mc.configPath.GetPath()), nil +} + +// LoadMachineByName returns a machine config based on the vm name and provider +func LoadMachineByName(name, configDir string) (*MachineConfig, error) { + fullPath := filepath.Join(configDir, fmt.Sprintf("%s.json", name)) + return loadMachineFromFQPath(fullPath) +} + +// loadMachineFromFQPath stub function for loading a JSON configuration file and returning +// a machineconfig. this should only be called if you know what you are doing. +func loadMachineFromFQPath(path string) (*MachineConfig, error) { + mc := new(MachineConfig) + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + err = json.Unmarshal(b, mc) + return mc, err +} + +// LoadMachinesInDir returns all the machineconfigs located in given dir +func LoadMachinesInDir(configDir string) (map[string]*MachineConfig, error) { + mcs := make(map[string]*MachineConfig) + if err := filepath.WalkDir(configDir, func(path string, d fs.DirEntry, err error) error { + if strings.HasSuffix(d.Name(), ".json") { + fullPath := filepath.Join(configDir, d.Name()) + mc, err := loadMachineFromFQPath(fullPath) + if err != nil { + return err + } + mcs[mc.Name] = mc + } + return nil + }); err != nil { + return nil, err + } + return mcs, nil +} diff --git a/pkg/machine/wsl/config.go b/pkg/machine/wsl/config.go index a522a77f52..7748537b3c 100644 --- a/pkg/machine/wsl/config.go +++ b/pkg/machine/wsl/config.go @@ -27,7 +27,7 @@ func VirtualizationProvider() machine.VirtProvider { } // NewMachine initializes an instance of a wsl machine -func (p *WSLVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, error) { +func (p *WSLVirtualization) NewMachine(opts define.InitOptions) (machine.VM, error) { vm := new(MachineVM) if len(opts.USBs) > 0 { return nil, fmt.Errorf("USB host passthrough is not supported for WSL machines") diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go index 7405192e53..c9d9166fee 100644 --- a/pkg/machine/wsl/machine.go +++ b/pkg/machine/wsl/machine.go @@ -16,6 +16,8 @@ import ( "strings" "time" + "github.com/containers/podman/v4/pkg/machine/connection" + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/pkg/machine" "github.com/containers/podman/v4/pkg/machine/define" @@ -394,7 +396,7 @@ func getLegacyLastStart(vm *MachineVM) time.Time { // Init writes the json configuration file to the filesystem for // other verbs (start, stop) -func (v *MachineVM) Init(opts machine.InitOptions) (bool, error) { +func (v *MachineVM) Init(opts define.InitOptions) (bool, error) { var ( err error ) @@ -495,10 +497,10 @@ func (v *MachineVM) removeMachineImage() error { } func (v *MachineVM) removeSystemConnections() error { - return machine.RemoveConnections(v.Name, fmt.Sprintf("%s-root", v.Name)) + return connection.RemoveConnections(v.Name, fmt.Sprintf("%s-root", v.Name)) } -func downloadDistro(v *MachineVM, opts machine.InitOptions) error { +func downloadDistro(v *MachineVM, opts define.InitOptions) error { var ( dd machine.DistributionDownload err error @@ -525,8 +527,8 @@ func (v *MachineVM) writeConfig() error { } func constructSSHUris(v *MachineVM) ([]url.URL, []string) { - uri := machine.SSHRemoteConnection.MakeSSHURL(machine.LocalhostIP, rootlessSock, strconv.Itoa(v.Port), v.RemoteUsername) - uriRoot := machine.SSHRemoteConnection.MakeSSHURL(machine.LocalhostIP, rootfulSock, strconv.Itoa(v.Port), "root") + uri := connection.SSHRemoteConnection.MakeSSHURL(connection.LocalhostIP, rootlessSock, strconv.Itoa(v.Port), v.RemoteUsername) + uriRoot := connection.SSHRemoteConnection.MakeSSHURL(connection.LocalhostIP, rootfulSock, strconv.Itoa(v.Port), "root") uris := []url.URL{uri, uriRoot} names := []string{v.Name, v.Name + "-root"} @@ -534,7 +536,7 @@ func constructSSHUris(v *MachineVM) ([]url.URL, []string) { return uris, names } -func setupConnections(v *MachineVM, opts machine.InitOptions) error { +func setupConnections(v *MachineVM, opts define.InitOptions) error { uris, names := constructSSHUris(v) // The first connection defined when connections is empty will become the default @@ -552,7 +554,7 @@ func setupConnections(v *MachineVM, opts machine.InitOptions) error { defer flock.unlock() for i := 0; i < 2; i++ { - if err := machine.AddConnection(&uris[i], names[i], v.IdentityPath, opts.IsDefault && i == 0); err != nil { + if err := connection.AddConnection(&uris[i], names[i], v.IdentityPath, opts.IsDefault && i == 0); err != nil { return err } } @@ -809,7 +811,7 @@ func writeWslConf(dist string, user string) error { return nil } -func checkAndInstallWSL(opts machine.InitOptions) (bool, error) { +func checkAndInstallWSL(opts define.InitOptions) (bool, error) { if wutil.IsWSLInstalled() { return true, nil } @@ -844,7 +846,7 @@ func checkAndInstallWSL(opts machine.InitOptions) (bool, error) { return true, nil } -func attemptFeatureInstall(opts machine.InitOptions, admin bool) error { +func attemptFeatureInstall(opts define.InitOptions, admin bool) error { if !winVersionAtLeast(10, 0, 18362) { return errors.New("your version of Windows does not support WSL. Update to Windows 10 Build 19041 or later") } else if !winVersionAtLeast(10, 0, 19041) { @@ -1276,7 +1278,7 @@ func (v *MachineVM) reassignSshPort() error { v.Port = newPort uris, names := constructSSHUris(v) for i := 0; i < 2; i++ { - if err := machine.ChangeConnectionURI(names[i], &uris[i]); err != nil { + if err := connection.ChangeConnectionURI(names[i], &uris[i]); err != nil { return err } } @@ -1476,7 +1478,7 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun confirmationMessage += "\n" return confirmationMessage, func() error { - if err := machine.RemoveConnections(v.Name, v.Name+"-root"); err != nil { + if err := connection.RemoveConnections(v.Name, v.Name+"-root"); err != nil { logrus.Error(err) } if err := runCmdPassThrough("wsl", "--unregister", toDist(v.Name)); err != nil {