spiegel_podman/pkg/machine/e2e/machine_test.go
Brent Baude ea4775ec9e Consume OCI images for machine image
allow podman machine to extract its disk image from an oci registry or
oci-dir locally.  for now, the image must be relatively inflexible. it
must have 1 layer.  the layer must possess one image. so a dockerfile
like:

FROM scratch
COPY ./myimage.xz /myimage.xz

when using an oci dir, the directory structure must adhere to the
typical directory structure of a an oci image (with one layer).

── blobs
│   └── sha256
│       ├── 53735773573b3853bb1cae16dd21061beb416239ceb78d4ef1f2a0609f7e843b
│       ├── 80577866ec13c041693e17de61444b4696137623803c3d87f92e4f28a1f4e87b
│       └── af57637ac1ab12f833e3cfa886027cc9834a755a437d0e1cf48b5d4778af7a4e
├── index.json
└── oci-layout

in order to identify this new input, you must use a transport/schema to
differentiate from current podman machine init --image-path behavior. we
will support `oci-dir://` and `docker://` as transports.

when using the docker transport, you can only use an empty transport for
input.  for example, `podman machine init --image-path docker://`.  A
fully quailified image name will be supported in the next iteration.

the transport absent anything means, i want to pull the default fcos
image stored in a registry.  podman will determine its current version
and then look for its correlating manifest.  in this default use case,
it would look for:

quay.io/libpod/podman-machine-images:<version>

that manifest would then point to specific images that contain the
correct arch and provider disk image. i.e.

quay.io/libpod/podman-machine-images:4.6-qcow2

this PR does not enable something like
docker://quay.io/mycorp/myimage:latest yet.

names, addresses, andf schema/transports are all subject to change. the
plan is to keep this all undocumented until things firm up.

[NO NEW TESTS NEEDED]

Signed-off-by: Brent Baude <bbaude@redhat.com>
2023-11-02 10:23:14 -05:00

159 lines
4.5 KiB
Go

package e2e_test
import (
"fmt"
"io"
url2 "net/url"
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
"github.com/containers/podman/v4/pkg/machine"
"github.com/containers/podman/v4/pkg/machine/provider"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
const (
defaultStream machine.FCOSStream = machine.Testing
)
var (
tmpDir = os.TempDir()
fqImageName string
suiteImageName string
)
func init() {
if value, ok := os.LookupEnv("TMPDIR"); ok {
tmpDir = value
}
}
// TestLibpod ginkgo master function
func TestMachine(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Podman Machine tests")
}
var testProvider machine.VirtProvider
var _ = BeforeSuite(func() {
var err error
testProvider, err = provider.Get()
if err != nil {
Fail("unable to create testProvider")
}
downloadLocation := os.Getenv("MACHINE_IMAGE")
if len(downloadLocation) < 1 {
downloadLocation = getDownloadLocation(testProvider)
// we cannot simply use OS here because hyperv uses fcos; so WSL is just
// special here
if testProvider.VMType() != machine.WSLVirt {
downloadLocation = getDownloadLocation(testProvider)
}
}
compressionExtension := fmt.Sprintf(".%s", testProvider.Compression().String())
suiteImageName = strings.TrimSuffix(path.Base(downloadLocation), compressionExtension)
fqImageName = filepath.Join(tmpDir, suiteImageName)
if _, err := os.Stat(fqImageName); err != nil {
if os.IsNotExist(err) {
getMe, err := url2.Parse(downloadLocation)
if err != nil {
Fail(fmt.Sprintf("unable to create url for download: %q", err))
}
now := time.Now()
if err := machine.DownloadVMImage(getMe, suiteImageName, fqImageName+compressionExtension); err != nil {
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)
if err != nil {
Fail(fmt.Sprintf("unable to create vmfile %q: %v", fqImageName+compressionExtension, err))
}
if err := machine.Decompress(diskImage, fqImageName); err != nil {
Fail(fmt.Sprintf("unable to decompress image file: %q", err))
}
} else {
Fail(fmt.Sprintf("unable to check for cache image: %q", err))
}
}
})
var _ = SynchronizedAfterSuite(func() {}, func() {})
func setup() (string, *machineTestBuilder) {
// Set TMPDIR if this needs a new directory
homeDir, err := os.MkdirTemp("", "podman_test")
if err != nil {
Fail(fmt.Sprintf("failed to create home directory: %q", err))
}
if err := os.MkdirAll(filepath.Join(homeDir, ".ssh"), 0700); err != nil {
Fail(fmt.Sprintf("failed to create ssh dir: %q", err))
}
sshConfig, err := os.Create(filepath.Join(homeDir, ".ssh", "config"))
if err != nil {
Fail(fmt.Sprintf("failed to create ssh config: %q", err))
}
if _, err := sshConfig.WriteString("IdentitiesOnly=yes"); err != nil {
Fail(fmt.Sprintf("failed to write ssh config: %q", err))
}
if err := sshConfig.Close(); err != nil {
Fail(fmt.Sprintf("unable to close ssh config file descriptor: %q", err))
}
if err := os.Setenv("HOME", homeDir); err != nil {
Fail("failed to set home dir")
}
if err := os.Setenv("XDG_RUNTIME_DIR", homeDir); err != nil {
Fail("failed to set xdg_runtime dir")
}
if err := os.Unsetenv("SSH_AUTH_SOCK"); err != nil {
Fail("unable to unset SSH_AUTH_SOCK")
}
mb, err := newMB()
if err != nil {
Fail(fmt.Sprintf("failed to create machine test: %q", err))
}
f, err := os.Open(fqImageName)
if err != nil {
Fail(fmt.Sprintf("failed to open file %s: %q", fqImageName, err))
}
mb.imagePath = filepath.Join(homeDir, suiteImageName)
n, err := os.Create(mb.imagePath)
if err != nil {
Fail(fmt.Sprintf("failed to create file %s: %q", mb.imagePath, err))
}
if _, err := io.Copy(n, f); err != nil {
Fail(fmt.Sprintf("failed to copy %ss to %s: %q", fqImageName, mb.imagePath, err))
}
if err := n.Close(); err != nil {
Fail(fmt.Sprintf("failed to close image copy handler: %q", err))
}
return homeDir, mb
}
func teardown(origHomeDir string, testDir string, mb *machineTestBuilder) {
r := new(rmMachine)
for _, name := range mb.names {
if _, err := mb.setName(name).setCmd(r.withForce()).run(); err != nil {
GinkgoWriter.Printf("error occurred rm'ing machine: %q\n", err)
}
}
if err := machine.GuardedRemoveAll(testDir); err != nil {
Fail(fmt.Sprintf("failed to remove test dir: %q", err))
}
// this needs to be last in teardown
if err := os.Setenv("HOME", origHomeDir); err != nil {
Fail("failed to set home dir")
}
}