Refactor key machine objects

In #20538, I was asked to consider refactoring the new OCI pull code
from within the generic machine directory.  This is something I had
tried when originally coding it but it became apparent that a much
larger refactor to prevent circular deps was needed.  Because I did not
want to pollute the initial PR with that refactor, I asked for the PR to
merge first.  This is the refactor that needed to be done.

Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
Brent Baude
2023-11-02 12:32:50 -05:00
parent f47a85f4ff
commit a45ba06d02
33 changed files with 783 additions and 657 deletions

View File

@ -11,6 +11,8 @@ import (
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
vfConfig "github.com/crc-org/vfkit/pkg/config"
"github.com/docker/go-units"
"golang.org/x/sys/unix"
@ -34,7 +36,7 @@ type MMHardwareConfig struct {
func VirtualizationProvider() machine.VirtProvider {
return &AppleHVVirtualization{
machine.NewVirtualization(machine.AppleHV, machine.Xz, machine.Raw, vmtype),
machine.NewVirtualization(define.AppleHV, compression.Xz, define.Raw, vmtype),
}
}
@ -116,7 +118,7 @@ func (v AppleHVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
return nil, err
}
configPath, err := machine.NewMachineFile(getVMConfigPath(configDir, opts.Name), nil)
configPath, err := define.NewMachineFile(getVMConfigPath(configDir, opts.Name), nil)
if err != nil {
return nil, err
}
@ -127,7 +129,7 @@ func (v AppleHVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
return nil, err
}
ignitionPath, err := machine.NewMachineFile(filepath.Join(configDir, m.Name)+".ign", nil)
ignitionPath, err := define.NewMachineFile(filepath.Join(configDir, m.Name)+".ign", nil)
if err != nil {
return nil, err
}

View File

@ -7,13 +7,13 @@ import (
"net"
"net/http"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/sirupsen/logrus"
)
// serveIgnitionOverSock allows podman to open a small httpd instance on the vsock between the host
// and guest to inject the ignitionfile into fcos
func (m *MacMachine) serveIgnitionOverSock(ignitionSocket *machine.VMFile) error {
func (m *MacMachine) serveIgnitionOverSock(ignitionSocket *define.VMFile) error {
logrus.Debugf("reading ignition file: %s", m.IgnitionFile.GetPath())
ignFile, err := m.IgnitionFile.Read()
if err != nil {

View File

@ -20,6 +20,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/define"
"github.com/containers/podman/v4/pkg/strongunits"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
@ -45,13 +46,13 @@ const (
type VfkitHelper struct {
LogLevel logrus.Level
Endpoint string
VfkitBinaryPath *machine.VMFile
VfkitBinaryPath *define.VMFile
VirtualMachine *vfConfig.VirtualMachine
}
type MacMachine struct {
// ConfigPath is the fully qualified path to the configuration file
ConfigPath machine.VMFile
ConfigPath define.VMFile
// HostUser contains info about host user
machine.HostUser
// ImageConfig describes the bootable image
@ -61,7 +62,7 @@ type MacMachine struct {
// Name of VM
Name string
// ReadySocket tells host when vm is booted
ReadySocket machine.VMFile
ReadySocket define.VMFile
// ResourceConfig is physical attrs of the VM
machine.ResourceConfig
// SSHConfig for accessing the remote vm
@ -74,9 +75,9 @@ type MacMachine struct {
LastUp time.Time
// The VFKit endpoint where we can interact with the VM
Vfkit VfkitHelper
LogPath machine.VMFile
GvProxyPid machine.VMFile
GvProxySock machine.VMFile
LogPath define.VMFile
GvProxyPid define.VMFile
GvProxySock define.VMFile
// Used at runtime for serializing write operations
lock *lockfile.LockFile
@ -84,7 +85,7 @@ type MacMachine struct {
// setGVProxyInfo sets the VM's gvproxy pid and socket files
func (m *MacMachine) setGVProxyInfo(runtimeDir string) error {
gvProxyPid, err := machine.NewMachineFile(filepath.Join(runtimeDir, "gvproxy.pid"), nil)
gvProxyPid, err := define.NewMachineFile(filepath.Join(runtimeDir, "gvproxy.pid"), nil)
if err != nil {
return err
}
@ -95,7 +96,7 @@ func (m *MacMachine) setGVProxyInfo(runtimeDir string) error {
// setVfkitInfo stores the default devices, sets the vfkit endpoint, and
// locates/stores the path to the binary
func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket machine.VMFile) error {
func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket define.VMFile) error {
defaultDevices, err := getDefaultDevices(m.ImagePath.GetPath(), m.LogPath.GetPath(), readySocket.GetPath())
if err != nil {
return err
@ -105,7 +106,7 @@ func (m *MacMachine) setVfkitInfo(cfg *config.Config, readySocket machine.VMFile
if err != nil {
return err
}
vfkitBinaryPath, err := machine.NewMachineFile(vfkitPath, nil)
vfkitBinaryPath, err := define.NewMachineFile(vfkitPath, nil)
if err != nil {
return err
}
@ -217,7 +218,7 @@ func (m *MacMachine) Init(opts machine.InitOptions) (bool, error) {
m.ImagePath = *imagePath
m.ImageStream = strm.String()
logPath, err := machine.NewMachineFile(filepath.Join(dataDir, fmt.Sprintf("%s.log", m.Name)), nil)
logPath, err := define.NewMachineFile(filepath.Join(dataDir, fmt.Sprintf("%s.log", m.Name)), nil)
if err != nil {
return false, err
}
@ -490,7 +491,7 @@ func (m *MacMachine) SSH(name string, opts machine.SSHOptions) error {
// deleteIgnitionSocket retrieves the ignition socket, deletes it, and returns a
// pointer to the `VMFile`
func (m *MacMachine) deleteIgnitionSocket() (*machine.VMFile, error) {
func (m *MacMachine) deleteIgnitionSocket() (*define.VMFile, error) {
ignitionSocket, err := m.getIgnitionSock()
if err != nil {
return nil, err
@ -556,7 +557,7 @@ func (m *MacMachine) addVolumesToVfKit() error {
}
func (m *MacMachine) Start(name string, opts machine.StartOptions) error {
var ignitionSocket *machine.VMFile
var ignitionSocket *define.VMFile
m.lock.Lock()
defer m.lock.Unlock()
@ -996,13 +997,13 @@ func (m *MacMachine) dockerSock() (string, error) {
return filepath.Join(dd, "podman.sock"), nil
}
func (m *MacMachine) forwardSocketPath() (*machine.VMFile, error) {
func (m *MacMachine) forwardSocketPath() (*define.VMFile, error) {
sockName := "podman.sock"
path, err := machine.GetDataDir(machine.AppleHvVirt)
if err != nil {
return nil, fmt.Errorf("Resolving data dir: %s", err.Error())
}
return machine.NewMachineFile(filepath.Join(path, sockName), &sockName)
return define.NewMachineFile(filepath.Join(path, sockName), &sockName)
}
// resizeDisk uses os truncate to resize (only larger) a raw disk. the input size
@ -1034,7 +1035,7 @@ func (m *MacMachine) isFirstBoot() (bool, error) {
return m.LastUp == never, nil
}
func (m *MacMachine) getIgnitionSock() (*machine.VMFile, error) {
func (m *MacMachine) getIgnitionSock() (*define.VMFile, error) {
dataDir, err := machine.GetDataDir(machine.AppleHvVirt)
if err != nil {
return nil, err
@ -1044,7 +1045,7 @@ func (m *MacMachine) getIgnitionSock() (*machine.VMFile, error) {
return nil, err
}
}
return machine.NewMachineFile(filepath.Join(dataDir, ignitionSocketName), nil)
return define.NewMachineFile(filepath.Join(dataDir, ignitionSocketName), nil)
}
func (m *MacMachine) getRuntimeDir() (string, error) {

View File

@ -0,0 +1,91 @@
package compression
import "testing"
func Test_compressionFromFile(t *testing.T) {
type args struct {
path string
}
var tests = []struct {
name string
args args
want ImageCompression
}{
{
name: "xz",
args: args{
path: "/tmp/foo.xz",
},
want: Xz,
},
{
name: "gzip",
args: args{
path: "/tmp/foo.gz",
},
want: Gz,
},
{
name: "bz2",
args: args{
path: "/tmp/foo.bz2",
},
want: Bz2,
},
{
name: "default is xz",
args: args{
path: "/tmp/foo",
},
want: Xz,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := KindFromFile(tt.args.path); got != tt.want {
t.Errorf("KindFromFile() = %v, want %v", got, tt.want)
}
})
}
}
func TestImageCompression_String(t *testing.T) {
tests := []struct {
name string
c ImageCompression
want string
}{
{
name: "xz",
c: Xz,
want: "xz",
},
{
name: "gz",
c: Gz,
want: "gz",
},
{
name: "bz2",
c: Bz2,
want: "bz2",
},
{
name: "zip",
c: Zip,
want: "zip",
},
{
name: "xz is default",
c: 99,
want: "xz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.c.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,36 @@
package compression
import "strings"
type ImageCompression int64
const (
Xz ImageCompression = iota
Zip
Gz
Bz2
)
func KindFromFile(path string) ImageCompression {
switch {
case strings.HasSuffix(path, Bz2.String()):
return Bz2
case strings.HasSuffix(path, Gz.String()):
return Gz
case strings.HasSuffix(path, Zip.String()):
return Zip
}
return Xz
}
func (c ImageCompression) String() string {
switch c {
case Gz:
return "gz"
case Zip:
return "zip"
case Bz2:
return "bz2"
}
return "xz"
}

View File

@ -0,0 +1,184 @@
package compression
import (
"archive/zip"
"bufio"
"errors"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/archive"
"github.com/sirupsen/logrus"
"github.com/ulikunitz/xz"
)
func Decompress(localPath *define.VMFile, uncompressedPath string) error {
var isZip bool
uncompressedFileWriter, err := os.OpenFile(uncompressedPath, os.O_CREATE|os.O_RDWR, 0600)
if err != nil {
return err
}
sourceFile, err := localPath.Read()
if err != nil {
return err
}
if strings.HasSuffix(localPath.GetPath(), ".zip") {
isZip = true
}
prefix := "Copying uncompressed file"
compressionType := archive.DetectCompression(sourceFile)
if compressionType != archive.Uncompressed || isZip {
prefix = "Extracting compressed file"
}
prefix += ": " + filepath.Base(uncompressedPath)
if compressionType == archive.Xz {
return decompressXZ(prefix, localPath.GetPath(), uncompressedFileWriter)
}
if isZip && runtime.GOOS == "windows" {
return decompressZip(prefix, localPath.GetPath(), uncompressedFileWriter)
}
return decompressEverythingElse(prefix, localPath.GetPath(), uncompressedFileWriter)
}
// Will error out if file without .Xz already exists
// Maybe extracting then renaming is a good idea here..
// depends on Xz: not pre-installed on mac, so it becomes a brew dependency
func decompressXZ(prefix string, src string, output io.WriteCloser) error {
var read io.Reader
var cmd *exec.Cmd
stat, err := os.Stat(src)
if err != nil {
return err
}
file, err := os.Open(src)
if err != nil {
return err
}
defer file.Close()
p, bar := utils.ProgressBar(prefix, stat.Size(), prefix+": done")
proxyReader := bar.ProxyReader(file)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
// Prefer Xz utils for fastest performance, fallback to go xi2 impl
if _, err := exec.LookPath("xz"); err == nil {
cmd = exec.Command("xz", "-d", "-c")
cmd.Stdin = proxyReader
read, err = cmd.StdoutPipe()
if err != nil {
return err
}
cmd.Stderr = os.Stderr
} else {
// This XZ implementation is reliant on buffering. It is also 3x+ slower than XZ utils.
// Consider replacing with a faster implementation (e.g. xi2) if podman machine is
// updated with a larger image for the distribution base.
buf := bufio.NewReader(proxyReader)
read, err = xz.NewReader(buf)
if err != nil {
return err
}
}
done := make(chan bool)
go func() {
if _, err := io.Copy(output, read); err != nil {
logrus.Error(err)
}
output.Close()
done <- true
}()
if cmd != nil {
err := cmd.Start()
if err != nil {
return err
}
p.Wait()
return cmd.Wait()
}
<-done
p.Wait()
return nil
}
func decompressEverythingElse(prefix string, src string, output io.WriteCloser) error {
stat, err := os.Stat(src)
if err != nil {
return err
}
f, err := os.Open(src)
if err != nil {
return err
}
p, bar := utils.ProgressBar(prefix, stat.Size(), prefix+": done")
proxyReader := bar.ProxyReader(f)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
uncompressStream, _, err := compression.AutoDecompress(proxyReader)
if err != nil {
return err
}
defer func() {
if err := uncompressStream.Close(); err != nil {
logrus.Error(err)
}
if err := output.Close(); err != nil {
logrus.Error(err)
}
}()
_, err = io.Copy(output, uncompressStream)
p.Wait()
return err
}
func decompressZip(prefix string, src string, output io.WriteCloser) error {
zipReader, err := zip.OpenReader(src)
if err != nil {
return err
}
if len(zipReader.File) != 1 {
return errors.New("machine image files should consist of a single compressed file")
}
f, err := zipReader.File[0].Open()
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
logrus.Error(err)
}
}()
defer func() {
if err := output.Close(); err != nil {
logrus.Error(err)
}
}()
size := int64(zipReader.File[0].CompressedSize64)
p, bar := utils.ProgressBar(prefix, size, prefix+": done")
proxyReader := bar.ProxyReader(f)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
_, err = io.Copy(output, proxyReader)
p.Wait()
return err
}

View File

@ -15,6 +15,8 @@ import (
"strings"
"time"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/lockfile"
"github.com/sirupsen/logrus"
@ -64,11 +66,11 @@ var (
type Download struct {
Arch string
Artifact Artifact
Artifact define.Artifact
CacheDir string
CompressionType ImageCompression
CompressionType compression.ImageCompression
DataDir string
Format ImageFormat
Format define.ImageFormat
ImageName string
LocalPath string
LocalUncompressedFile string
@ -162,7 +164,7 @@ type DistributionDownload interface {
CleanCache() error
}
type InspectInfo struct {
ConfigPath VMFile
ConfigPath define.VMFile
ConnectionInfo ConnectionConfig
Created time.Time
Image ImageConfig
@ -269,15 +271,6 @@ func ConfDirPrefix() (string, error) {
return confDir, nil
}
// GuardedRemoveAll functions much like os.RemoveAll but
// will not delete certain catastrophic paths.
func GuardedRemoveAll(path string) error {
if path == "" || path == "/" {
return fmt.Errorf("refusing to recursively delete `%s`", path)
}
return os.RemoveAll(path)
}
// ResourceConfig describes physical attributes of the machine
type ResourceConfig struct {
// CPUs to be assigned to the VM
@ -288,77 +281,6 @@ type ResourceConfig struct {
Memory uint64
}
const maxSocketPathLength int = 103
type VMFile struct {
// Path is the fully qualified path to a file
Path string
// Symlink is a shortened version of Path by using
// a symlink
Symlink *string `json:"symlink,omitempty"`
}
// GetPath returns the working path for a machinefile. it returns
// the symlink unless one does not exist
func (m *VMFile) GetPath() string {
if m.Symlink == nil {
return m.Path
}
return *m.Symlink
}
// Delete removes the machinefile symlink (if it exists) and
// the actual path
func (m *VMFile) Delete() error {
if m.Symlink != nil {
if err := os.Remove(*m.Symlink); err != nil && !errors.Is(err, os.ErrNotExist) {
logrus.Errorf("unable to remove symlink %q", *m.Symlink)
}
}
if err := os.Remove(m.Path); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
return nil
}
// Read the contents of a given file and return in []bytes
func (m *VMFile) Read() ([]byte, error) {
return os.ReadFile(m.GetPath())
}
// NewMachineFile is a constructor for VMFile
func NewMachineFile(path string, symlink *string) (*VMFile, error) {
if len(path) < 1 {
return nil, errors.New("invalid machine file path")
}
if symlink != nil && len(*symlink) < 1 {
return nil, errors.New("invalid symlink path")
}
mf := VMFile{Path: path}
if symlink != nil && len(path) > maxSocketPathLength {
if err := mf.makeSymlink(symlink); err != nil && !errors.Is(err, os.ErrExist) {
return nil, err
}
}
return &mf, nil
}
// makeSymlink for macOS creates a symlink in $HOME/.podman/
// for a machinefile like a socket
func (m *VMFile) makeSymlink(symlink *string) error {
homeDir, err := os.UserHomeDir()
if err != nil {
return err
}
sl := filepath.Join(homeDir, ".podman", *symlink)
// make the symlink dir and throw away if it already exists
if err := os.MkdirAll(filepath.Dir(sl), 0700); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
m.Symlink = &sl
return os.Symlink(m.Path, sl)
}
type Mount struct {
ReadOnly bool
Source string
@ -371,11 +293,11 @@ type Mount struct {
type ImageConfig struct {
// IgnitionFile is the path to the filesystem where the
// ignition file was written (if needs one)
IgnitionFile VMFile `json:"IgnitionFilePath"`
IgnitionFile define.VMFile `json:"IgnitionFilePath"`
// ImageStream is the update stream for the image
ImageStream string
// ImageFile is the fq path to
ImagePath VMFile `json:"ImagePath"`
ImagePath define.VMFile `json:"ImagePath"`
}
// HostUser describes the host user
@ -401,9 +323,9 @@ type SSHConfig struct {
// ConnectionConfig contains connections like sockets, etc.
type ConnectionConfig struct {
// PodmanSocket is the exported podman service socket
PodmanSocket *VMFile `json:"PodmanSocket"`
PodmanSocket *define.VMFile `json:"PodmanSocket"`
// PodmanPipe is the exported podman service named pipe (Windows hosts only)
PodmanPipe *VMFile `json:"PodmanPipe"`
PodmanPipe *define.VMFile `json:"PodmanPipe"`
}
type VMType int64
@ -455,10 +377,10 @@ func ParseVMType(input string, emptyFallback VMType) (VMType, error) {
}
type VirtProvider interface { //nolint:interfacebloat
Artifact() Artifact
Artifact() define.Artifact
CheckExclusiveActiveVM() (bool, string, error)
Compression() ImageCompression
Format() ImageFormat
Compression() compression.ImageCompression
Format() define.ImageFormat
IsValidVMName(name string) (bool, error)
List(opts ListOptions) ([]*ListResponse, error)
LoadVMByName(name string) (VM, error)
@ -469,21 +391,21 @@ type VirtProvider interface { //nolint:interfacebloat
}
type Virtualization struct {
artifact Artifact
compression ImageCompression
format ImageFormat
artifact define.Artifact
compression compression.ImageCompression
format define.ImageFormat
vmKind VMType
}
func (p *Virtualization) Artifact() Artifact {
func (p *Virtualization) Artifact() define.Artifact {
return p.artifact
}
func (p *Virtualization) Compression() ImageCompression {
func (p *Virtualization) Compression() compression.ImageCompression {
return p.compression
}
func (p *Virtualization) Format() ImageFormat {
func (p *Virtualization) Format() define.ImageFormat {
return p.format
}
@ -513,7 +435,7 @@ func (p *Virtualization) NewDownload(vmName string) (Download, error) {
}, nil
}
func NewVirtualization(artifact Artifact, compression ImageCompression, format ImageFormat, vmKind VMType) Virtualization {
func NewVirtualization(artifact define.Artifact, compression compression.ImageCompression, format define.ImageFormat, vmKind VMType) Virtualization {
return Virtualization{
artifact,
compression,
@ -579,10 +501,10 @@ func (dl Download) NewFcosDownloader(imageStream FCOSStream) (DistributionDownlo
// AcquireVMImage determines if the image is already in a FCOS stream. If so,
// retrieves the image path of the uncompressed file. Otherwise, the user has
// provided an alternative image, so we set the image path and download the image.
func (dl Download) AcquireVMImage(imagePath string) (*VMFile, FCOSStream, error) {
func (dl Download) AcquireVMImage(imagePath string) (*define.VMFile, FCOSStream, error) {
var (
err error
imageLocation *VMFile
imageLocation *define.VMFile
fcosStream FCOSStream
)
@ -600,7 +522,7 @@ func (dl Download) AcquireVMImage(imagePath string) (*VMFile, FCOSStream, error)
return nil, 0, err
}
imageLocation, err = NewMachineFile(dd.Get().LocalUncompressedFile, nil)
imageLocation, err = define.NewMachineFile(dd.Get().LocalUncompressedFile, nil)
if err != nil {
return nil, 0, err
}

View File

@ -0,0 +1,34 @@
package define
type ImageFormat int64
const (
Qcow ImageFormat = iota
Vhdx
Tar
Raw
)
func (imf ImageFormat) Kind() string {
switch imf {
case Vhdx:
return "vhdx"
case Tar:
return "tar"
case Raw:
return "raw"
}
return "qcow2"
}
func (imf ImageFormat) KindWithCompression() string {
switch imf {
case Vhdx:
return "vhdx.zip"
case Tar:
return "tar.xz"
case Raw:
return "raw.gz"
}
return "qcow2.xz"
}

View File

@ -0,0 +1,74 @@
package define
import "testing"
func TestImageFormat_Kind(t *testing.T) {
tests := []struct {
name string
imf ImageFormat
want string
}{
{
name: "vhdx",
imf: Vhdx,
want: "vhdx",
},
{
name: "qcow2",
imf: Qcow,
want: "qcow2",
},
{
name: "raw",
imf: Raw,
want: "raw",
},
{
name: "tar",
imf: Tar,
want: "tar",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.imf.Kind(); got != tt.want {
t.Errorf("Kind() = %v, want %v", got, tt.want)
}
})
}
}
func TestImageFormat_KindWithCompression(t *testing.T) {
tests := []struct {
name string
imf ImageFormat
want string
}{
{
name: "vhdx.zip",
imf: Vhdx,
want: "vhdx.zip",
},
{
name: "qcow2",
imf: Qcow,
want: "qcow2.xz",
},
{
name: "raw.gz",
imf: Raw,
want: "raw.gz",
}, {
name: "tar.xz",
imf: Tar,
want: "tar.xz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.imf.KindWithCompression(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,20 @@
package define
type Artifact int64
const (
Qemu Artifact = iota
HyperV
AppleHV
None
)
func (a Artifact) String() string {
switch a {
case HyperV:
return "hyperv"
case AppleHV:
return "applehv"
}
return "qemu"
}

View File

@ -0,0 +1,35 @@
package define
import (
"testing"
)
func Test_artifact_String(t *testing.T) {
tests := []struct {
name string
a Artifact
want string
}{
{
name: "qemu",
a: Qemu,
want: "qemu",
},
{
name: "hyperv",
a: HyperV,
want: "hyperv",
}, {
name: "applehv",
a: AppleHV,
want: "applehv",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.a.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,80 @@
package define
import (
"errors"
"os"
"path/filepath"
"github.com/sirupsen/logrus"
)
const MaxSocketPathLength int = 103
type VMFile struct {
// Path is the fully qualified path to a file
Path string
// Symlink is a shortened version of Path by using
// a symlink
Symlink *string `json:"symlink,omitempty"`
}
// GetPath returns the working path for a machinefile. it returns
// the symlink unless one does not exist
func (m *VMFile) GetPath() string {
if m.Symlink == nil {
return m.Path
}
return *m.Symlink
}
// Delete removes the machinefile symlink (if it exists) and
// the actual path
func (m *VMFile) Delete() error {
if m.Symlink != nil {
if err := os.Remove(*m.Symlink); err != nil && !errors.Is(err, os.ErrNotExist) {
logrus.Errorf("unable to remove symlink %q", *m.Symlink)
}
}
if err := os.Remove(m.Path); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
return nil
}
// Read the contents of a given file and return in []bytes
func (m *VMFile) Read() ([]byte, error) {
return os.ReadFile(m.GetPath())
}
// NewMachineFile is a constructor for VMFile
func NewMachineFile(path string, symlink *string) (*VMFile, error) {
if len(path) < 1 {
return nil, errors.New("invalid machine file path")
}
if symlink != nil && len(*symlink) < 1 {
return nil, errors.New("invalid symlink path")
}
mf := VMFile{Path: path}
if symlink != nil && len(path) > MaxSocketPathLength {
if err := mf.makeSymlink(symlink); err != nil && !errors.Is(err, os.ErrExist) {
return nil, err
}
}
return &mf, nil
}
// makeSymlink for macOS creates a symlink in $HOME/.podman/
// for a machinefile like a socket
func (m *VMFile) makeSymlink(symlink *string) error {
homeDir, err := os.UserHomeDir()
if err != nil {
return err
}
sl := filepath.Join(homeDir, ".podman", *symlink)
// make the symlink dir and throw away if it already exists
if err := os.MkdirAll(filepath.Dir(sl), 0700); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}
m.Symlink = &sl
return os.Symlink(m.Path, sl)
}

View File

@ -1,7 +1,7 @@
//go:build (amd64 && !windows) || (arm64 && !windows)
// +build amd64,!windows arm64,!windows
package qemu
package define
import (
"os"
@ -9,7 +9,6 @@ import (
"reflect"
"testing"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/test/utils"
)
@ -41,7 +40,7 @@ func TestMachineFile_GetPath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &machine.VMFile{
m := &VMFile{
Path: tt.fields.Path, //nolint: scopelint
Symlink: tt.fields.Symlink, //nolint: scopelint
}
@ -75,7 +74,7 @@ func TestNewMachineFile(t *testing.T) {
sym := "my.sock"
longSym := filepath.Join(homedir, ".podman", sym)
m := machine.VMFile{
m := VMFile{
Path: p,
Symlink: nil,
}
@ -86,7 +85,7 @@ func TestNewMachineFile(t *testing.T) {
tests := []struct {
name string
args args
want *machine.VMFile
want *VMFile
wantErr bool
}{
{
@ -98,7 +97,7 @@ func TestNewMachineFile(t *testing.T) {
{
name: "Good with short symlink",
args: args{p, &sym},
want: &machine.VMFile{Path: p},
want: &VMFile{Path: p},
wantErr: false,
},
{
@ -116,14 +115,14 @@ func TestNewMachineFile(t *testing.T) {
{
name: "Good with long symlink",
args: args{longp, &sym},
want: &machine.VMFile{Path: longp, Symlink: &longSym},
want: &VMFile{Path: longp, Symlink: &longSym},
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, err := machine.NewMachineFile(tt.args.path, tt.args.symlink)
got, err := NewMachineFile(tt.args.path, tt.args.symlink)
if (err != nil) != tt.wantErr {
t.Errorf("NewMachineFile() error = %v, wantErr %v", err, tt.wantErr)
return

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@ -188,7 +189,7 @@ var _ = Describe("podman machine init", func() {
_, err = os.CreateTemp(tmpDir, "example")
Expect(err).ToNot(HaveOccurred())
mount := tmpDir + ":/testmountdir"
defer func() { _ = machine.GuardedRemoveAll(tmpDir) }()
defer func() { _ = utils.GuardedRemoveAll(tmpDir) }()
name := randomString()
i := new(initMachine)

View File

@ -12,7 +12,10 @@ import (
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/pkg/machine/provider"
"github.com/containers/podman/v4/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
@ -77,11 +80,11 @@ var _ = BeforeSuite(func() {
Fail(fmt.Sprintf("unable to download machine image: %q", err))
}
GinkgoWriter.Println("Download took: ", time.Since(now).String())
diskImage, err := machine.NewMachineFile(fqImageName+compressionExtension, nil)
diskImage, err := define.NewMachineFile(fqImageName+compressionExtension, nil)
if err != nil {
Fail(fmt.Sprintf("unable to create vmfile %q: %v", fqImageName+compressionExtension, err))
}
if err := machine.Decompress(diskImage, fqImageName); err != nil {
if err := compression.Decompress(diskImage, fqImageName); err != nil {
Fail(fmt.Sprintf("unable to decompress image file: %q", err))
}
} else {
@ -149,7 +152,7 @@ func teardown(origHomeDir string, testDir string, mb *machineTestBuilder) {
GinkgoWriter.Printf("error occurred rm'ing machine: %q\n", err)
}
}
if err := machine.GuardedRemoveAll(testDir); err != nil {
if err := utils.GuardedRemoveAll(testDir); err != nil {
Fail(fmt.Sprintf("failed to remove test dir: %q", err))
}
// this needs to be last in teardown

View File

@ -11,9 +11,10 @@ import (
url2 "net/url"
"os"
"runtime"
"strings"
"time"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/coreos/stream-metadata-go/fedoracoreos"
"github.com/coreos/stream-metadata-go/release"
"github.com/coreos/stream-metadata-go/stream"
@ -21,31 +22,12 @@ import (
"github.com/sirupsen/logrus"
)
type ImageCompression int64
type Artifact int64
type ImageFormat int64
const (
// Used for testing the latest podman in fcos
// special builds
podmanTesting = "podman-testing"
PodmanTestingHost = "fedorapeople.org"
PodmanTestingURL = "groups/podman/testing"
Xz ImageCompression = iota
Zip
Gz
Bz2
Qemu Artifact = iota
HyperV
AppleHV
None
Qcow ImageFormat = iota
Vhdx
Tar
Raw
)
//
@ -56,64 +38,6 @@ const (
// typed strongly
//
func (a Artifact) String() string {
switch a {
case HyperV:
return "hyperv"
case AppleHV:
return "applehv"
}
return "qemu"
}
func (imf ImageFormat) String() string {
switch imf {
case Vhdx:
return "vhdx.zip"
case Tar:
return "tar.xz"
case Raw:
return "raw.gz"
}
return "qcow2.xz"
}
func (imf ImageFormat) string() string {
switch imf {
case Vhdx:
return "vhdx"
case Tar:
return "tar"
case Raw:
return "raw"
}
return "qcow2"
}
func (c ImageCompression) String() string {
switch c {
case Gz:
return "gz"
case Zip:
return "zip"
case Bz2:
return "bz2"
}
return "xz"
}
func compressionFromFile(path string) ImageCompression {
switch {
case strings.HasSuffix(path, Bz2.String()):
return Bz2
case strings.HasSuffix(path, Gz.String()):
return Gz
case strings.HasSuffix(path, Zip.String()):
return Zip
}
return Xz
}
type FcosDownload struct {
Download
}
@ -123,7 +47,7 @@ func (f FcosDownload) Get() *Download {
}
type FcosDownloadInfo struct {
CompressionType ImageCompression
CompressionType compression.ImageCompression
Location string
Release string
Sha256Sum string
@ -219,7 +143,7 @@ func (dl Download) GetFCOSDownload(imageStream FCOSStream) (*FcosDownloadInfo, e
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no targetArch in stream")
}
qcow2, ok := arches.Media.Qemu.Artifacts[Qcow.String()]
qcow2, ok := arches.Media.Qemu.Artifacts[define.Qcow.KindWithCompression()]
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no qcow2.xz format in stream")
}
@ -251,9 +175,9 @@ func (dl Download) GetFCOSDownload(imageStream FCOSStream) (*FcosDownloadInfo, e
if formats == nil {
return nil, fmt.Errorf("unable to pull VM image: no formats in stream")
}
formatType, ok := formats[dl.Format.String()]
formatType, ok := formats[dl.Format.KindWithCompression()]
if !ok {
return nil, fmt.Errorf("unable to pull VM image: no %s format in stream", dl.Format.String())
return nil, fmt.Errorf("unable to pull VM image: no %s format in stream", dl.Format.KindWithCompression())
}
disk := formatType.Disk
if disk == nil {

View File

@ -7,146 +7,6 @@ import (
"testing"
)
func Test_compressionFromFile(t *testing.T) {
type args struct {
path string
}
var tests = []struct {
name string
args args
want ImageCompression
}{
{
name: "xz",
args: args{
path: "/tmp/foo.xz",
},
want: Xz,
},
{
name: "gzip",
args: args{
path: "/tmp/foo.gz",
},
want: Gz,
},
{
name: "bz2",
args: args{
path: "/tmp/foo.bz2",
},
want: Bz2,
},
{
name: "default is xz",
args: args{
path: "/tmp/foo",
},
want: Xz,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := compressionFromFile(tt.args.path); got != tt.want {
t.Errorf("compressionFromFile() = %v, want %v", got, tt.want)
}
})
}
}
func TestImageCompression_String(t *testing.T) {
tests := []struct {
name string
c ImageCompression
want string
}{
{
name: "xz",
c: Xz,
want: "xz",
},
{
name: "gz",
c: Gz,
want: "gz",
},
{
name: "bz2",
c: Bz2,
want: "bz2",
},
{
name: "zip",
c: Zip,
want: "zip",
},
{
name: "xz is default",
c: 99,
want: "xz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.c.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}
func TestImageFormat_String(t *testing.T) {
tests := []struct {
name string
imf ImageFormat
want string
}{
{
name: "vhdx.zip",
imf: Vhdx,
want: "vhdx.zip",
},
{
name: "qcow2",
imf: Qcow,
want: "qcow2.xz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.imf.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}
func Test_artifact_String(t *testing.T) {
tests := []struct {
name string
a Artifact
want string
}{
{
name: "qemu",
a: Qemu,
want: "qemu",
},
{
name: "hyperv",
a: HyperV,
want: "hyperv",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.a.String(); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}
func TestFCOSStream_String(t *testing.T) {
tests := []struct {
name string

View File

@ -8,6 +8,7 @@ import (
"syscall"
"time"
"github.com/containers/podman/v4/pkg/machine/define"
psutil "github.com/shirou/gopsutil/v3/process"
"github.com/sirupsen/logrus"
)
@ -82,7 +83,7 @@ func waitOnProcess(processID int) error {
}
// CleanupGVProxy reads the --pid-file for gvproxy attempts to stop it
func CleanupGVProxy(f VMFile) error {
func CleanupGVProxy(f define.VMFile) error {
gvPid, err := f.Read()
if err != nil {
return fmt.Errorf("unable to read gvproxy pid file %s: %v", f.GetPath(), err)

View File

@ -14,6 +14,8 @@ import (
"github.com/containers/libhvee/pkg/hypervctl"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
)
@ -24,7 +26,7 @@ type HyperVVirtualization struct {
func VirtualizationProvider() machine.VirtProvider {
return &HyperVVirtualization{
machine.NewVirtualization(machine.HyperV, machine.Zip, machine.Vhdx, vmtype),
machine.NewVirtualization(define.HyperV, compression.Zip, define.Vhdx, vmtype),
}
}
@ -117,14 +119,14 @@ func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
return nil, err
}
configPath, err := machine.NewMachineFile(getVMConfigPath(configDir, opts.Name), nil)
configPath, err := define.NewMachineFile(getVMConfigPath(configDir, opts.Name), nil)
if err != nil {
return nil, err
}
m.ConfigPath = *configPath
ignitionPath, err := machine.NewMachineFile(filepath.Join(configDir, m.Name)+".ign", nil)
ignitionPath, err := define.NewMachineFile(filepath.Join(configDir, m.Name)+".ign", nil)
if err != nil {
return nil, err
}
@ -139,7 +141,7 @@ func (v HyperVVirtualization) NewMachine(opts machine.InitOptions) (machine.VM,
}
// Set the proxy pid file
gvProxyPid, err := machine.NewMachineFile(filepath.Join(dataDir, "gvproxy.pid"), nil)
gvProxyPid, err := define.NewMachineFile(filepath.Join(dataDir, "gvproxy.pid"), nil)
if err != nil {
return nil, err
}

View File

@ -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/define"
"github.com/containers/podman/v4/pkg/strongunits"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
@ -44,7 +45,7 @@ const (
type HyperVMachine struct {
// ConfigPath is the fully qualified path to the configuration file
ConfigPath machine.VMFile
ConfigPath define.VMFile
// HostUser contains info about host user
machine.HostUser
// ImageConfig describes the bootable image
@ -68,7 +69,7 @@ type HyperVMachine struct {
// LastUp contains the last recorded uptime
LastUp time.Time
// GVProxy will write its PID here
GvProxyPid machine.VMFile
GvProxyPid define.VMFile
// MountVsocks contains the currently-active vsocks, mapped to the
// directory they should be mounted on.
MountVsocks map[string]uint64
@ -873,13 +874,13 @@ func (m *HyperVMachine) dockerSock() (string, error) {
return filepath.Join(dd, "podman.sock"), nil
}
func (m *HyperVMachine) forwardSocketPath() (*machine.VMFile, error) {
func (m *HyperVMachine) forwardSocketPath() (*define.VMFile, error) {
sockName := "podman.sock"
path, err := machine.GetDataDir(machine.HyperVVirt)
if err != nil {
return nil, fmt.Errorf("Resolving data dir: %s", err.Error())
}
return machine.NewMachineFile(filepath.Join(path, sockName), &sockName)
return define.NewMachineFile(filepath.Join(path, sockName), &sockName)
}
func (m *HyperVMachine) writeConfig() error {

View File

@ -1,4 +1,4 @@
package machine
package ocipull
import (
"fmt"
@ -6,14 +6,13 @@ import (
"path/filepath"
"strings"
"github.com/containers/image/v5/types"
"github.com/blang/semver/v4"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/version"
"github.com/containers/storage/pkg/archive"
"github.com/sirupsen/logrus"
"github.com/blang/semver/v4"
"github.com/containers/podman/v4/version"
)
// quay.io/libpod/podman-machine-images:4.6
@ -30,9 +29,9 @@ type OSVersion struct {
type Disker interface {
Pull() error
Decompress(compressedFile *VMFile) (*VMFile, error)
Decompress(compressedFile *define.VMFile) (*define.VMFile, error)
DiskEndpoint() string
Unpack() (*VMFile, error)
Unpack() (*define.VMFile, error)
}
type OCIOpts struct {
@ -81,11 +80,11 @@ func (o *OSVersion) majorMinor() string {
return fmt.Sprintf("%d.%d", o.Major, o.Minor)
}
func (o *OSVersion) diskImage(diskFlavor ImageFormat) string {
return fmt.Sprintf("%s/%s/%s:%s-%s", registry, repo, diskImages, o.majorMinor(), diskFlavor.string())
func (o *OSVersion) diskImage(diskFlavor define.ImageFormat) string {
return fmt.Sprintf("%s/%s/%s:%s-%s", registry, repo, diskImages, o.majorMinor(), diskFlavor.Kind())
}
func unpackOCIDir(ociTb, machineImageDir string) (*VMFile, error) {
func unpackOCIDir(ociTb, machineImageDir string) (*define.VMFile, error) {
imageFileName, err := findTarComponent(ociTb)
if err != nil {
return nil, err
@ -121,7 +120,7 @@ func unpackOCIDir(ociTb, machineImageDir string) (*VMFile, error) {
return nil, err
}
return NewMachineFile(unpackedFileName, nil)
return define.NewMachineFile(unpackedFileName, nil)
}
func localOCIDiskImageDir(blobDirPath string, localBlob *types.BlobInfo) string {

View File

@ -1,4 +1,4 @@
package machine
package ocipull
import (
"archive/tar"
@ -11,7 +11,8 @@ import (
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/machine/ocipull"
diskcompression "github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/sirupsen/logrus"
)
@ -38,7 +39,7 @@ func NewOCIDir(ctx context.Context, inputDir, machineImageDir, vmName string) *L
}
func (l *LocalBlobDir) Pull() error {
localBlob, err := ocipull.GetLocalBlob(l.ctx, l.DiskEndpoint())
localBlob, err := GetLocalBlob(l.ctx, l.DiskEndpoint())
if err != nil {
return err
}
@ -46,15 +47,15 @@ func (l *LocalBlobDir) Pull() error {
return nil
}
func (l *LocalBlobDir) Decompress(compressedFile *VMFile) (*VMFile, error) {
func (l *LocalBlobDir) Decompress(compressedFile *define.VMFile) (*define.VMFile, error) {
finalName := finalFQImagePathName(l.vmName, l.imageName)
if err := Decompress(compressedFile, finalName); err != nil {
if err := diskcompression.Decompress(compressedFile, finalName); err != nil {
return nil, err
}
return NewMachineFile(finalName, nil)
return define.NewMachineFile(finalName, nil)
}
func (l *LocalBlobDir) Unpack() (*VMFile, error) {
func (l *LocalBlobDir) Unpack() (*define.VMFile, error) {
tbPath := localOCIDiskImageDir(l.blobDirPath, l.blob)
unPackedFile, err := unpackOCIDir(tbPath, l.machineImageDir)
if err != nil {

View File

@ -1,4 +1,4 @@
package machine
package ocipull
import (
"context"
@ -8,7 +8,9 @@ import (
"strings"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/pkg/machine/ocipull"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/utils"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/sirupsen/logrus"
)
@ -18,14 +20,14 @@ type Versioned struct {
blobDirPath string
cacheDir string
ctx context.Context
imageFormat ImageFormat
imageFormat define.ImageFormat
imageName string
machineImageDir string
machineVersion *OSVersion
vmName string
}
func newVersioned(ctx context.Context, machineImageDir, vmName string) (*Versioned, error) {
func NewVersioned(ctx context.Context, machineImageDir, vmName string) (*Versioned, error) {
imageCacheDir := filepath.Join(machineImageDir, "cache")
if err := os.MkdirAll(imageCacheDir, 0777); err != nil {
return nil, err
@ -47,7 +49,7 @@ func (d *Versioned) versionedOCICacheDir() string {
}
func (d *Versioned) identifyImageNameFromOCIDir() (string, error) {
imageManifest, err := ocipull.ReadImageManifestFromOCIPath(d.ctx, d.versionedOCICacheDir())
imageManifest, err := ReadImageManifestFromOCIPath(d.ctx, d.versionedOCICacheDir())
if err != nil {
return "", err
}
@ -61,7 +63,7 @@ func (d *Versioned) identifyImageNameFromOCIDir() (string, error) {
func (d *Versioned) pull(path string) error {
fmt.Printf("Pulling %s\n", d.DiskEndpoint())
logrus.Debugf("pulling %s to %s", d.DiskEndpoint(), path)
return ocipull.Pull(d.ctx, d.DiskEndpoint(), path, ocipull.PullOptions{})
return Pull(d.ctx, d.DiskEndpoint(), path, PullOptions{})
}
func (d *Versioned) Pull() error {
@ -72,7 +74,7 @@ func (d *Versioned) Pull() error {
remoteDescriptor *v1.Descriptor
)
remoteDiskImage := d.machineVersion.diskImage(Qcow)
remoteDiskImage := d.machineVersion.diskImage(define.Qcow)
logrus.Debugf("podman disk image name: %s", remoteDiskImage)
// is there a valid oci dir in our cache
@ -80,12 +82,12 @@ func (d *Versioned) Pull() error {
if hasCache {
logrus.Debug("checking remote registry")
remoteDescriptor, err = ocipull.GetRemoteDescriptor(d.ctx, remoteDiskImage)
remoteDescriptor, err = GetRemoteDescriptor(d.ctx, remoteDiskImage)
if err != nil {
return err
}
logrus.Debugf("working with local cache: %s", d.versionedOCICacheDir())
localBlob, err = ocipull.GetLocalBlob(d.ctx, d.versionedOCICacheDir())
localBlob, err = GetLocalBlob(d.ctx, d.versionedOCICacheDir())
if err != nil {
return err
}
@ -97,7 +99,7 @@ func (d *Versioned) Pull() error {
}
if !hasCache || isUpdatable {
if hasCache {
if err := GuardedRemoveAll(d.versionedOCICacheDir()); err != nil {
if err := utils.GuardedRemoveAll(d.versionedOCICacheDir()); err != nil {
return err
}
}
@ -113,7 +115,7 @@ func (d *Versioned) Pull() error {
d.imageName = imageName
if localBlob == nil {
localBlob, err = ocipull.GetLocalBlob(d.ctx, d.versionedOCICacheDir())
localBlob, err = GetLocalBlob(d.ctx, d.versionedOCICacheDir())
if err != nil {
return err
}
@ -124,7 +126,7 @@ func (d *Versioned) Pull() error {
return nil
}
func (d *Versioned) Unpack() (*VMFile, error) {
func (d *Versioned) Unpack() (*define.VMFile, error) {
tbPath := localOCIDiskImageDir(d.blobDirPath, d.blob)
unpackedFile, err := unpackOCIDir(tbPath, d.machineImageDir)
if err != nil {
@ -134,14 +136,14 @@ func (d *Versioned) Unpack() (*VMFile, error) {
return unpackedFile, nil
}
func (d *Versioned) Decompress(compressedFile *VMFile) (*VMFile, error) {
imageCompression := compressionFromFile(d.imageName)
func (d *Versioned) Decompress(compressedFile *define.VMFile) (*define.VMFile, error) {
imageCompression := compression.KindFromFile(d.imageName)
strippedImageName := strings.TrimSuffix(d.imageName, fmt.Sprintf(".%s", imageCompression.String()))
finalName := finalFQImagePathName(d.vmName, strippedImageName)
if err := Decompress(compressedFile, finalName); err != nil {
if err := compression.Decompress(compressedFile, finalName); err != nil {
return nil, err
}
return NewMachineFile(finalName, nil)
return define.NewMachineFile(finalName, nil)
}
func (d *Versioned) localOCIDiskImageDir(localBlob *types.BlobInfo) string {

View File

@ -4,8 +4,6 @@
package machine
import (
"archive/zip"
"bufio"
"context"
"errors"
"fmt"
@ -13,18 +11,15 @@ import (
"net/http"
url2 "net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/storage/pkg/archive"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/pkg/machine/ocipull"
"github.com/containers/podman/v4/utils"
"github.com/sirupsen/logrus"
"github.com/ulikunitz/xz"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
)
// GenericDownload is used when a user provides a URL
@ -90,7 +85,7 @@ func supportedURL(path string) (url *url2.URL) {
func (dl Download) GetLocalUncompressedFile(dataDir string) string {
compressedFilename := dl.VMName + "_" + dl.ImageName
extension := compressionFromFile(compressedFilename)
extension := compression.KindFromFile(compressedFilename)
uncompressedFile := strings.TrimSuffix(compressedFilename, fmt.Sprintf(".%s", extension.String()))
dl.LocalUncompressedFile = filepath.Join(dataDir, uncompressedFile)
return dl.LocalUncompressedFile
@ -134,33 +129,11 @@ func DownloadImage(d DistributionDownload) error {
}
}()
}
localPath, err := NewMachineFile(d.Get().LocalPath, nil)
localPath, err := define.NewMachineFile(d.Get().LocalPath, nil)
if err != nil {
return err
}
return Decompress(localPath, d.Get().LocalUncompressedFile)
}
func progressBar(prefix string, size int64, onComplete string) (*mpb.Progress, *mpb.Bar) {
p := mpb.New(
mpb.WithWidth(80), // Do not go below 80, see bug #17718
mpb.WithRefreshRate(180*time.Millisecond),
)
bar := p.AddBar(size,
mpb.BarFillerClearOnComplete(),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(prefix), onComplete),
),
mpb.AppendDecorators(
decor.OnComplete(decor.CountersKibiByte("%.1f / %.1f"), ""),
),
)
if size == 0 {
bar.SetTotal(0, true)
}
return p, bar
return compression.Decompress(localPath, d.Get().LocalUncompressedFile)
}
// DownloadVMImage downloads a VM image from url to given path
@ -193,7 +166,7 @@ func DownloadVMImage(downloadURL *url2.URL, imageName string, localImagePath str
prefix := "Downloading VM image: " + imageName
onComplete := prefix + ": done"
p, bar := progressBar(prefix, size, onComplete)
p, bar := utils.ProgressBar(prefix, size, onComplete)
proxyReader := bar.ProxyReader(resp.Body)
defer func() {
@ -210,170 +183,6 @@ func DownloadVMImage(downloadURL *url2.URL, imageName string, localImagePath str
return nil
}
func Decompress(localPath *VMFile, uncompressedPath string) error {
var isZip bool
uncompressedFileWriter, err := os.OpenFile(uncompressedPath, os.O_CREATE|os.O_RDWR, 0600)
if err != nil {
return err
}
sourceFile, err := localPath.Read()
if err != nil {
return err
}
if strings.HasSuffix(localPath.GetPath(), ".zip") {
isZip = true
}
prefix := "Copying uncompressed file"
compressionType := archive.DetectCompression(sourceFile)
if compressionType != archive.Uncompressed || isZip {
prefix = "Extracting compressed file"
}
prefix += ": " + filepath.Base(uncompressedPath)
if compressionType == archive.Xz {
return decompressXZ(prefix, localPath.GetPath(), uncompressedFileWriter)
}
if isZip && runtime.GOOS == "windows" {
return decompressZip(prefix, localPath.GetPath(), uncompressedFileWriter)
}
return decompressEverythingElse(prefix, localPath.GetPath(), uncompressedFileWriter)
}
// Will error out if file without .Xz already exists
// Maybe extracting then renaming is a good idea here..
// depends on Xz: not pre-installed on mac, so it becomes a brew dependency
func decompressXZ(prefix string, src string, output io.WriteCloser) error {
var read io.Reader
var cmd *exec.Cmd
stat, err := os.Stat(src)
if err != nil {
return err
}
file, err := os.Open(src)
if err != nil {
return err
}
defer file.Close()
p, bar := progressBar(prefix, stat.Size(), prefix+": done")
proxyReader := bar.ProxyReader(file)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
// Prefer Xz utils for fastest performance, fallback to go xi2 impl
if _, err := exec.LookPath("xz"); err == nil {
cmd = exec.Command("xz", "-d", "-c")
cmd.Stdin = proxyReader
read, err = cmd.StdoutPipe()
if err != nil {
return err
}
cmd.Stderr = os.Stderr
} else {
// This XZ implementation is reliant on buffering. It is also 3x+ slower than XZ utils.
// Consider replacing with a faster implementation (e.g. xi2) if podman machine is
// updated with a larger image for the distribution base.
buf := bufio.NewReader(proxyReader)
read, err = xz.NewReader(buf)
if err != nil {
return err
}
}
done := make(chan bool)
go func() {
if _, err := io.Copy(output, read); err != nil {
logrus.Error(err)
}
output.Close()
done <- true
}()
if cmd != nil {
err := cmd.Start()
if err != nil {
return err
}
p.Wait()
return cmd.Wait()
}
<-done
p.Wait()
return nil
}
func decompressEverythingElse(prefix string, src string, output io.WriteCloser) error {
stat, err := os.Stat(src)
if err != nil {
return err
}
f, err := os.Open(src)
if err != nil {
return err
}
p, bar := progressBar(prefix, stat.Size(), prefix+": done")
proxyReader := bar.ProxyReader(f)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
uncompressStream, _, err := compression.AutoDecompress(proxyReader)
if err != nil {
return err
}
defer func() {
if err := uncompressStream.Close(); err != nil {
logrus.Error(err)
}
if err := output.Close(); err != nil {
logrus.Error(err)
}
}()
_, err = io.Copy(output, uncompressStream)
p.Wait()
return err
}
func decompressZip(prefix string, src string, output io.WriteCloser) error {
zipReader, err := zip.OpenReader(src)
if err != nil {
return err
}
if len(zipReader.File) != 1 {
return errors.New("machine image files should consist of a single compressed file")
}
f, err := zipReader.File[0].Open()
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
logrus.Error(err)
}
}()
defer func() {
if err := output.Close(); err != nil {
logrus.Error(err)
}
}()
size := int64(zipReader.File[0].CompressedSize64)
p, bar := progressBar(prefix, size, prefix+": done")
proxyReader := bar.ProxyReader(f)
defer func() {
if err := proxyReader.Close(); err != nil {
logrus.Error(err)
}
}()
_, err = io.Copy(output, proxyReader)
p.Wait()
return err
}
func RemoveImageAfterExpire(dir string, expire time.Duration) error {
now := time.Now()
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
@ -393,13 +202,13 @@ func RemoveImageAfterExpire(dir string, expire time.Duration) error {
// AcquireAlternateImage downloads the alternate image the user provided, which
// can be a file path or URL
func (dl Download) AcquireAlternateImage(inputPath string) (*VMFile, error) {
func (dl Download) AcquireAlternateImage(inputPath string) (*define.VMFile, error) {
g, err := NewGenericDownloader(dl.VMKind, dl.VMName, inputPath)
if err != nil {
return nil, err
}
imagePath, err := NewMachineFile(g.Get().LocalUncompressedFile, nil)
imagePath, err := define.NewMachineFile(g.Get().LocalUncompressedFile, nil)
if err != nil {
return nil, err
}
@ -411,23 +220,23 @@ func (dl Download) AcquireAlternateImage(inputPath string) (*VMFile, error) {
return imagePath, nil
}
func isOci(input string) (bool, *OCIKind, error) {
func isOci(input string) (bool, *ocipull.OCIKind, error) {
inputURL, err := url2.Parse(input)
if err != nil {
return false, nil, err
}
switch inputURL.Scheme {
case OCIDir.String():
return true, &OCIDir, nil
case OCIRegistry.String():
return true, &OCIRegistry, nil
case ocipull.OCIDir.String():
return true, &ocipull.OCIDir, nil
case ocipull.OCIRegistry.String():
return true, &ocipull.OCIRegistry, nil
}
return false, nil, nil
}
func Pull(input, machineName string, vp VirtProvider) (*VMFile, FCOSStream, error) {
func Pull(input, machineName string, vp VirtProvider) (*define.VMFile, FCOSStream, error) {
var (
disk Disker
disk ocipull.Disker
)
ociBased, ociScheme, err := isOci(input)
@ -442,7 +251,7 @@ func Pull(input, machineName string, vp VirtProvider) (*VMFile, FCOSStream, erro
}
return dl.AcquireVMImage(input)
}
oopts := OCIOpts{
oopts := ocipull.OCIOpts{
Scheme: ociScheme,
}
dataDir, err := GetDataDir(vp.VMType())
@ -450,9 +259,9 @@ func Pull(input, machineName string, vp VirtProvider) (*VMFile, FCOSStream, erro
return nil, 0, err
}
if ociScheme.IsOCIDir() {
strippedOCIDir := StripOCIReference(input)
strippedOCIDir := ocipull.StripOCIReference(input)
oopts.Dir = &strippedOCIDir
disk = NewOCIDir(context.Background(), input, dataDir, machineName)
disk = ocipull.NewOCIDir(context.Background(), input, dataDir, machineName)
} else {
// a use of a containers image type here might be
// tighter
@ -461,7 +270,7 @@ func Pull(input, machineName string, vp VirtProvider) (*VMFile, FCOSStream, erro
if len(strippedInput) > 0 {
return nil, 0, errors.New("image names are not supported yet")
}
disk, err = newVersioned(context.Background(), dataDir, machineName)
disk, err = ocipull.NewVersioned(context.Background(), dataDir, machineName)
if err != nil {
return nil, 0, err
}

View File

@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/define"
)
// QemuCmd is an alias around a string slice to prevent the need to migrate the
@ -30,7 +30,7 @@ func (q *QemuCmd) SetCPUs(c uint64) {
}
// SetIgnitionFile specifies the machine's ignition file
func (q *QemuCmd) SetIgnitionFile(file machine.VMFile) {
func (q *QemuCmd) SetIgnitionFile(file define.VMFile) {
*q = append(*q, "-fw_cfg", "name=opt/com.coreos/config,file="+file.GetPath())
}
@ -47,7 +47,7 @@ func (q *QemuCmd) SetNetwork() {
}
// SetSerialPort adds a serial port to the machine for readiness
func (q *QemuCmd) SetSerialPort(readySocket, vmPidFile machine.VMFile, name string) {
func (q *QemuCmd) SetSerialPort(readySocket, vmPidFile define.VMFile, name string) {
*q = append(*q,
"-device", "virtio-serial",
// qemu needs to establish the long name; other connections can use the symlink'd

View File

@ -11,6 +11,8 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/utils"
"github.com/docker/go-units"
"github.com/sirupsen/logrus"
@ -77,14 +79,14 @@ func (p *QEMUVirtualization) NewMachine(opts machine.InitOptions) (machine.VM, e
}
// set VM ignition file
ignitionFile, err := machine.NewMachineFile(filepath.Join(vmConfigDir, vm.Name+".ign"), nil)
ignitionFile, err := define.NewMachineFile(filepath.Join(vmConfigDir, vm.Name+".ign"), nil)
if err != nil {
return nil, err
}
vm.IgnitionFile = *ignitionFile
// set VM image file
imagePath, err := machine.NewMachineFile(opts.ImagePath, nil)
imagePath, err := define.NewMachineFile(opts.ImagePath, nil)
if err != nil {
return nil, err
}
@ -299,7 +301,7 @@ func (p *QEMUVirtualization) RemoveAndCleanMachines() error {
}
prevErr = err
} else {
err := machine.GuardedRemoveAll(dataDir)
err := utils.GuardedRemoveAll(dataDir)
if err != nil {
if prevErr != nil {
logrus.Error(prevErr)
@ -316,7 +318,7 @@ func (p *QEMUVirtualization) RemoveAndCleanMachines() error {
}
prevErr = err
} else {
err := machine.GuardedRemoveAll(confDir)
err := utils.GuardedRemoveAll(confDir)
if err != nil {
if prevErr != nil {
logrus.Error(prevErr)
@ -333,7 +335,7 @@ func (p *QEMUVirtualization) VMType() machine.VMType {
func VirtualizationProvider() machine.VirtProvider {
return &QEMUVirtualization{
machine.NewVirtualization(machine.Qemu, machine.Xz, machine.Qcow, vmtype),
machine.NewVirtualization(define.Qemu, compression.Xz, define.Qcow, vmtype),
}
}

View File

@ -24,6 +24,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/define"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/storage/pkg/lockfile"
@ -46,7 +47,7 @@ const (
type MachineVM struct {
// ConfigPath is the path to the configuration file
ConfigPath machine.VMFile
ConfigPath define.VMFile
// The command line representation of the qemu command
CmdLine QemuCmd
// HostUser contains info about host user
@ -58,13 +59,13 @@ type MachineVM struct {
// Name of VM
Name string
// PidFilePath is the where the Proxy PID file lives
PidFilePath machine.VMFile
PidFilePath define.VMFile
// VMPidFilePath is the where the VM PID file lives
VMPidFilePath machine.VMFile
VMPidFilePath define.VMFile
// QMPMonitor is the qemu monitor object for sending commands
QMPMonitor Monitor
// ReadySocket tells host when vm is booted
ReadySocket machine.VMFile
ReadySocket define.VMFile
// ResourceConfig is physical attrs of the VM
machine.ResourceConfig
// SSHConfig for accessing the remote vm
@ -82,7 +83,7 @@ type MachineVM struct {
type Monitor struct {
// Address portion of the qmp monitor (/tmp/tmp.sock)
Address machine.VMFile
Address define.VMFile
// Network portion of the qmp monitor (unix)
Network string
// Timeout in seconds for qmp monitor transactions
@ -105,9 +106,9 @@ func migrateVM(configPath string, config []byte, vm *MachineVM) error {
return err
}
pidFilePath := machine.VMFile{Path: pidFile}
pidFilePath := define.VMFile{Path: pidFile}
qmpMonitor := Monitor{
Address: machine.VMFile{Path: old.QMPMonitor.Address},
Address: define.VMFile{Path: old.QMPMonitor.Address},
Network: old.QMPMonitor.Network,
Timeout: old.QMPMonitor.Timeout,
}
@ -116,18 +117,18 @@ func migrateVM(configPath string, config []byte, vm *MachineVM) error {
return err
}
virtualSocketPath := filepath.Join(socketPath, "podman", vm.Name+"_ready.sock")
readySocket := machine.VMFile{Path: virtualSocketPath}
readySocket := define.VMFile{Path: virtualSocketPath}
vm.HostUser = machine.HostUser{}
vm.ImageConfig = machine.ImageConfig{}
vm.ResourceConfig = machine.ResourceConfig{}
vm.SSHConfig = machine.SSHConfig{}
ignitionFilePath, err := machine.NewMachineFile(old.IgnitionFilePath, nil)
ignitionFilePath, err := define.NewMachineFile(old.IgnitionFilePath, nil)
if err != nil {
return err
}
imagePath, err := machine.NewMachineFile(old.ImagePath, nil)
imagePath, err := define.NewMachineFile(old.ImagePath, nil)
if err != nil {
return err
}
@ -1030,7 +1031,7 @@ func NewQMPMonitor(network, name string, timeout time.Duration) (Monitor, error)
if timeout == 0 {
timeout = defaultQMPTimeout
}
address, err := machine.NewMachineFile(filepath.Join(rtDir, "qmp_"+name+".sock"), nil)
address, err := define.NewMachineFile(filepath.Join(rtDir, "qmp_"+name+".sock"), nil)
if err != nil {
return Monitor{}, err
}
@ -1350,14 +1351,14 @@ func (v *MachineVM) userGlobalSocketLink() (string, error) {
return filepath.Join(filepath.Dir(path), "podman.sock"), err
}
func (v *MachineVM) forwardSocketPath() (*machine.VMFile, error) {
func (v *MachineVM) forwardSocketPath() (*define.VMFile, error) {
sockName := "podman.sock"
path, err := machine.GetDataDir(machine.QemuVirt)
if err != nil {
logrus.Errorf("Resolving data dir: %s", err.Error())
return nil, err
}
return machine.NewMachineFile(filepath.Join(path, sockName), &sockName)
return define.NewMachineFile(filepath.Join(path, sockName), &sockName)
}
func (v *MachineVM) setConfigPath() error {
@ -1366,7 +1367,7 @@ func (v *MachineVM) setConfigPath() error {
return err
}
configPath, err := machine.NewMachineFile(filepath.Join(vmConfigDir, v.Name)+".json", nil)
configPath, err := define.NewMachineFile(filepath.Join(vmConfigDir, v.Name)+".json", nil)
if err != nil {
return err
}
@ -1385,11 +1386,11 @@ func (v *MachineVM) setPIDSocket() error {
socketDir := filepath.Join(rtPath, "podman")
vmPidFileName := fmt.Sprintf("%s_vm.pid", v.Name)
proxyPidFileName := fmt.Sprintf("%s_proxy.pid", v.Name)
vmPidFilePath, err := machine.NewMachineFile(filepath.Join(socketDir, vmPidFileName), &vmPidFileName)
vmPidFilePath, err := define.NewMachineFile(filepath.Join(socketDir, vmPidFileName), &vmPidFileName)
if err != nil {
return err
}
proxyPidFilePath, err := machine.NewMachineFile(filepath.Join(socketDir, proxyPidFileName), &proxyPidFileName)
proxyPidFilePath, err := define.NewMachineFile(filepath.Join(socketDir, proxyPidFileName), &proxyPidFileName)
if err != nil {
return err
}

View File

@ -7,22 +7,22 @@ import (
"fmt"
"testing"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestQemuCmd(t *testing.T) {
ignFile, err := machine.NewMachineFile(t.TempDir()+"demo-ignition-file.ign", nil)
ignFile, err := define.NewMachineFile(t.TempDir()+"demo-ignition-file.ign", nil)
assert.NoError(t, err)
machineAddrFile, err := machine.NewMachineFile(t.TempDir()+"tmp.sock", nil)
machineAddrFile, err := define.NewMachineFile(t.TempDir()+"tmp.sock", nil)
assert.NoError(t, err)
readySocket, err := machine.NewMachineFile(t.TempDir()+"readySocket.sock", nil)
readySocket, err := define.NewMachineFile(t.TempDir()+"readySocket.sock", nil)
assert.NoError(t, err)
vmPidFile, err := machine.NewMachineFile(t.TempDir()+"vmpidfile.pid", nil)
vmPidFile, err := define.NewMachineFile(t.TempDir()+"vmpidfile.pid", nil)
assert.NoError(t, err)
monitor := Monitor{

View File

@ -7,12 +7,14 @@ import (
"net"
"path/filepath"
"time"
"github.com/containers/podman/v4/pkg/machine/define"
)
// SetSocket creates a new machine file for the socket and assigns it to
// `socketLoc`
func SetSocket(socketLoc *VMFile, path string, symlink *string) error {
socket, err := NewMachineFile(path, symlink)
func SetSocket(socketLoc *define.VMFile, path string, symlink *string) error {
socket, err := define.NewMachineFile(path, symlink)
if err != nil {
return err
}

View File

@ -10,6 +10,9 @@ import (
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/compression"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/utils"
"github.com/sirupsen/logrus"
)
@ -19,7 +22,7 @@ type WSLVirtualization struct {
func VirtualizationProvider() machine.VirtProvider {
return &WSLVirtualization{
machine.NewVirtualization(machine.None, machine.Xz, machine.Tar, vmtype),
machine.NewVirtualization(define.None, compression.Xz, define.Tar, vmtype),
}
}
@ -196,7 +199,7 @@ func (p *WSLVirtualization) RemoveAndCleanMachines() error {
}
prevErr = err
} else {
err := machine.GuardedRemoveAll(dataDir)
err := utils.GuardedRemoveAll(dataDir)
if err != nil {
if prevErr != nil {
logrus.Error(prevErr)
@ -213,7 +216,7 @@ func (p *WSLVirtualization) RemoveAndCleanMachines() error {
}
prevErr = err
} else {
err := machine.GuardedRemoveAll(confDir)
err := utils.GuardedRemoveAll(confDir)
if err != nil {
if prevErr != nil {
logrus.Error(prevErr)

View File

@ -16,6 +16,7 @@ import (
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/define"
)
const (
@ -43,9 +44,9 @@ func NewFedoraDownloader(vmType machine.VMType, vmName, releaseStream string) (m
f := FedoraDownload{
Download: machine.Download{
Arch: machine.GetFcosArch(),
Artifact: machine.None,
Artifact: define.None,
CacheDir: cacheDir,
Format: machine.Tar,
Format: define.Tar,
ImageName: imageName,
LocalPath: filepath.Join(cacheDir, imageName),
URL: downloadURL,

View File

@ -19,8 +19,10 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/define"
"github.com/containers/podman/v4/pkg/machine/wsl/wutil"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
"github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/lockfile"
"github.com/sirupsen/logrus"
@ -480,22 +482,22 @@ func (v *MachineVM) unprovisionWSL() error {
}
distDir := filepath.Join(vmDataDir, "wsldist")
distTarget := filepath.Join(distDir, v.Name)
return machine.GuardedRemoveAll(distTarget)
return utils.GuardedRemoveAll(distTarget)
}
func (v *MachineVM) removeMachineConfig() error {
return machine.GuardedRemoveAll(v.ConfigPath)
return utils.GuardedRemoveAll(v.ConfigPath)
}
func (v *MachineVM) removeMachineImage() error {
return machine.GuardedRemoveAll(v.ImagePath)
return utils.GuardedRemoveAll(v.ImagePath)
}
func (v *MachineVM) removeSSHKeys() error {
if err := machine.GuardedRemoveAll(fmt.Sprintf("%s.pub", v.IdentityPath)); err != nil {
if err := utils.GuardedRemoveAll(fmt.Sprintf("%s.pub", v.IdentityPath)); err != nil {
logrus.Error(err)
}
return machine.GuardedRemoveAll(v.IdentityPath)
return utils.GuardedRemoveAll(v.IdentityPath)
}
func (v *MachineVM) removeSystemConnections() error {
@ -1635,7 +1637,7 @@ func (v *MachineVM) Remove(name string, opts machine.RemoveOptions) (string, fun
logrus.Error(err)
}
for _, f := range files {
if err := machine.GuardedRemoveAll(f); err != nil {
if err := utils.GuardedRemoveAll(f); err != nil {
logrus.Error(err)
}
}
@ -1804,15 +1806,15 @@ func (v *MachineVM) Inspect() (*machine.InspectInfo, error) {
connInfo := new(machine.ConnectionConfig)
machinePipe := toDist(v.Name)
connInfo.PodmanPipe = &machine.VMFile{Path: `\\.\pipe\` + machinePipe}
connInfo.PodmanPipe = &define.VMFile{Path: `\\.\pipe\` + machinePipe}
created, lastUp, _ := v.updateTimeStamps(state == machine.Running)
return &machine.InspectInfo{
ConfigPath: machine.VMFile{Path: v.ConfigPath},
ConfigPath: define.VMFile{Path: v.ConfigPath},
ConnectionInfo: *connInfo,
Created: created,
Image: machine.ImageConfig{
ImagePath: machine.VMFile{Path: v.ImagePath},
ImagePath: define.VMFile{Path: v.ImagePath},
ImageStream: v.ImageStream,
},
LastUp: lastUp,

View File

@ -10,12 +10,15 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/containers/common/pkg/cgroups"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
"github.com/godbus/dbus/v5"
"github.com/sirupsen/logrus"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
)
// ExecCmd executes a command with args and returns its output as a string along
@ -242,3 +245,34 @@ func MaybeMoveToSubCgroup() error {
})
return maybeMoveToSubCgroupSyncErr
}
// GuardedRemoveAll functions much like os.RemoveAll but
// will not delete certain catastrophic paths.
func GuardedRemoveAll(path string) error {
if path == "" || path == "/" {
return fmt.Errorf("refusing to recursively delete `%s`", path)
}
return os.RemoveAll(path)
}
func ProgressBar(prefix string, size int64, onComplete string) (*mpb.Progress, *mpb.Bar) {
p := mpb.New(
mpb.WithWidth(80), // Do not go below 80, see bug #17718
mpb.WithRefreshRate(180*time.Millisecond),
)
bar := p.AddBar(size,
mpb.BarFillerClearOnComplete(),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(prefix), onComplete),
),
mpb.AppendDecorators(
decor.OnComplete(decor.CountersKibiByte("%.1f / %.1f"), ""),
),
)
if size == 0 {
bar.SetTotal(0, true)
}
return p, bar
}