mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
7a9cb29fb9
This enables image lookup when creating a container to fail when the reference exists but it is for the wrong platform. This prevents trying to run an image for the wrong platform, as can be the case with, for example binfmt_misc+qemu. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
182 lines
4.8 KiB
Go
182 lines
4.8 KiB
Go
package fakestorage // import "github.com/docker/docker/testutil/fakestorage"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
containertypes "github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/testutil"
|
|
"github.com/docker/docker/testutil/environment"
|
|
"github.com/docker/docker/testutil/fakecontext"
|
|
"github.com/docker/docker/testutil/request"
|
|
"github.com/docker/go-connections/nat"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
var testEnv *environment.Execution
|
|
|
|
// Fake is a static file server. It might be running locally or remotely
|
|
// on test host.
|
|
type Fake interface {
|
|
Close() error
|
|
URL() string
|
|
CtxDir() string
|
|
}
|
|
|
|
// SetTestEnvironment sets a static test environment
|
|
// TODO: decouple this package from environment
|
|
func SetTestEnvironment(env *environment.Execution) {
|
|
testEnv = env
|
|
}
|
|
|
|
// New returns a static file server that will be use as build context.
|
|
func New(t testing.TB, dir string, modifiers ...func(*fakecontext.Fake) error) Fake {
|
|
t.Helper()
|
|
if testEnv == nil {
|
|
t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.")
|
|
}
|
|
ctx := fakecontext.New(t, dir, modifiers...)
|
|
switch {
|
|
case testEnv.IsRemoteDaemon() && strings.HasPrefix(request.DaemonHost(), "unix:///"):
|
|
t.Skip("e2e run : daemon is remote but docker host points to a unix socket")
|
|
case testEnv.IsLocalDaemon():
|
|
return newLocalFakeStorage(ctx)
|
|
default:
|
|
return newRemoteFileServer(t, ctx, testEnv.APIClient())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// localFileStorage is a file storage on the running machine
|
|
type localFileStorage struct {
|
|
*fakecontext.Fake
|
|
*httptest.Server
|
|
}
|
|
|
|
func (s *localFileStorage) URL() string {
|
|
return s.Server.URL
|
|
}
|
|
|
|
func (s *localFileStorage) CtxDir() string {
|
|
return s.Fake.Dir
|
|
}
|
|
|
|
func (s *localFileStorage) Close() error {
|
|
defer s.Server.Close()
|
|
return s.Fake.Close()
|
|
}
|
|
|
|
func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage {
|
|
handler := http.FileServer(http.Dir(ctx.Dir))
|
|
server := httptest.NewServer(handler)
|
|
return &localFileStorage{
|
|
Fake: ctx,
|
|
Server: server,
|
|
}
|
|
}
|
|
|
|
// remoteFileServer is a containerized static file server started on the remote
|
|
// testing machine to be used in URL-accepting docker build functionality.
|
|
type remoteFileServer struct {
|
|
host string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
|
|
container string
|
|
image string
|
|
client client.APIClient
|
|
ctx *fakecontext.Fake
|
|
}
|
|
|
|
func (f *remoteFileServer) URL() string {
|
|
u := url.URL{
|
|
Scheme: "http",
|
|
Host: f.host}
|
|
return u.String()
|
|
}
|
|
|
|
func (f *remoteFileServer) CtxDir() string {
|
|
return f.ctx.Dir
|
|
}
|
|
|
|
func (f *remoteFileServer) Close() error {
|
|
defer func() {
|
|
if f.ctx != nil {
|
|
f.ctx.Close()
|
|
}
|
|
if f.image != "" {
|
|
if _, err := f.client.ImageRemove(context.Background(), f.image, types.ImageRemoveOptions{
|
|
Force: true,
|
|
}); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
|
|
}
|
|
}
|
|
if err := f.client.Close(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
|
|
}
|
|
}()
|
|
if f.container == "" {
|
|
return nil
|
|
}
|
|
return f.client.ContainerRemove(context.Background(), f.container, types.ContainerRemoveOptions{
|
|
Force: true,
|
|
RemoveVolumes: true,
|
|
})
|
|
}
|
|
|
|
func newRemoteFileServer(t testing.TB, ctx *fakecontext.Fake, c client.APIClient) *remoteFileServer {
|
|
var (
|
|
image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
|
|
container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
|
|
)
|
|
|
|
ensureHTTPServerImage(t)
|
|
|
|
// Build the image
|
|
if err := ctx.Add("Dockerfile", `FROM httpserver
|
|
COPY . /static`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp, err := c.ImageBuild(context.Background(), ctx.AsTarReader(t), types.ImageBuildOptions{
|
|
NoCache: true,
|
|
Tags: []string{image},
|
|
})
|
|
assert.NilError(t, err)
|
|
_, err = io.Copy(ioutil.Discard, resp.Body)
|
|
assert.NilError(t, err)
|
|
|
|
// Start the container
|
|
b, err := c.ContainerCreate(context.Background(), &containertypes.Config{
|
|
Image: image,
|
|
}, &containertypes.HostConfig{}, nil, nil, container)
|
|
assert.NilError(t, err)
|
|
err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{})
|
|
assert.NilError(t, err)
|
|
|
|
// Find out the system assigned port
|
|
i, err := c.ContainerInspect(context.Background(), b.ID)
|
|
assert.NilError(t, err)
|
|
newP, err := nat.NewPort("tcp", "80")
|
|
assert.NilError(t, err)
|
|
ports, exists := i.NetworkSettings.Ports[newP]
|
|
if !exists || len(ports) != 1 {
|
|
t.Fatalf("unable to find port 80/tcp for %s", container)
|
|
}
|
|
host := ports[0].HostIP
|
|
port := ports[0].HostPort
|
|
|
|
return &remoteFileServer{
|
|
container: container,
|
|
image: image,
|
|
host: fmt.Sprintf("%s:%s", host, port),
|
|
ctx: ctx,
|
|
client: c,
|
|
}
|
|
}
|