Move FakeContext to integration-cli/cli/build/context
package…
… and continue emptying `docker_utils_test.go` from build related function. Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
a258ef58d8
commit
56fb4653e8
13 changed files with 1011 additions and 935 deletions
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/docker/docker/api/types/swarm"
|
||||
cliconfig "github.com/docker/docker/cli/config"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakestorage"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/integration-cli/environment"
|
||||
"github.com/docker/docker/integration-cli/registry"
|
||||
|
@ -65,6 +66,7 @@ func TestMain(m *testing.M) {
|
|||
|
||||
func Test(t *testing.T) {
|
||||
cli.EnsureTestEnvIsLoaded(t)
|
||||
fakestorage.EnsureTestEnvIsLoaded(t)
|
||||
cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
|
||||
cmd.Env = appendBaseEnv(true)
|
||||
out, err := cmd.CombinedOutput()
|
||||
|
|
|
@ -1,11 +1,30 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
icmd "github.com/docker/docker/pkg/testutil/cmd"
|
||||
)
|
||||
|
||||
type testingT interface {
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
// WithStdinContext sets the build context from the standard input with the specified reader
|
||||
func WithStdinContext(closer io.ReadCloser) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Command = append(cmd.Command, "-")
|
||||
cmd.Stdin = closer
|
||||
return func() {
|
||||
// FIXME(vdemeester) we should not ignore the error here…
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithDockerfile creates / returns a CmdOperator to set the Dockerfile for a build operation
|
||||
func WithDockerfile(dockerfile string) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
|
@ -28,3 +47,36 @@ func WithContextPath(path string) func(*icmd.Cmd) func() {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithExternalBuildContext use the specified context as build context
|
||||
func WithExternalBuildContext(ctx *fakecontext.Fake) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBuildContext sets up the build context
|
||||
func WithBuildContext(t testingT, contextOperators ...func(*fakecontext.Fake) error) func(*icmd.Cmd) func() {
|
||||
// FIXME(vdemeester) de-duplicate that
|
||||
ctx := fakecontext.New(t, "", contextOperators...)
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return closeBuildContext(t, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFile adds the specified file (with content) in the build context
|
||||
func WithFile(name, content string) func(*fakecontext.Fake) error {
|
||||
return fakecontext.WithFile(name, content)
|
||||
}
|
||||
|
||||
func closeBuildContext(t testingT, ctx *fakecontext.Fake) func() {
|
||||
return func() {
|
||||
if err := ctx.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
112
integration-cli/cli/build/fakecontext/context.go
Normal file
112
integration-cli/cli/build/fakecontext/context.go
Normal file
|
@ -0,0 +1,112 @@
|
|||
package fakecontext
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type testingT interface {
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
// New creates a fake build context
|
||||
func New(t testingT, dir string, modifiers ...func(*Fake) error) *Fake {
|
||||
fakeContext := &Fake{Dir: dir}
|
||||
if dir == "" {
|
||||
if err := newDir(fakeContext); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, modifier := range modifiers {
|
||||
if err := modifier(fakeContext); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
return fakeContext
|
||||
}
|
||||
|
||||
func newDir(fake *Fake) error {
|
||||
tmp, err := ioutil.TempDir("", "fake-context")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Chmod(tmp, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
fake.Dir = tmp
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithFile adds the specified file (with content) in the build context
|
||||
func WithFile(name, content string) func(*Fake) error {
|
||||
return func(ctx *Fake) error {
|
||||
return ctx.Add(name, content)
|
||||
}
|
||||
}
|
||||
|
||||
// WithDockerfile adds the specified content as Dockerfile in the build context
|
||||
func WithDockerfile(content string) func(*Fake) error {
|
||||
return WithFile("Dockerfile", content)
|
||||
}
|
||||
|
||||
// WithFiles adds the specified files in the build context, content is a string
|
||||
func WithFiles(files map[string]string) func(*Fake) error {
|
||||
return func(fakeContext *Fake) error {
|
||||
for file, content := range files {
|
||||
if err := fakeContext.Add(file, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBinaryFiles adds the specified files in the build context, content is binary
|
||||
func WithBinaryFiles(files map[string]*bytes.Buffer) func(*Fake) error {
|
||||
return func(fakeContext *Fake) error {
|
||||
for file, content := range files {
|
||||
if err := fakeContext.Add(file, string(content.Bytes())); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Fake creates directories that can be used as a build context
|
||||
type Fake struct {
|
||||
Dir string
|
||||
}
|
||||
|
||||
// Add a file at a path, creating directories where necessary
|
||||
func (f *Fake) Add(file, content string) error {
|
||||
return f.addFile(file, []byte(content))
|
||||
}
|
||||
|
||||
func (f *Fake) addFile(file string, content []byte) error {
|
||||
fp := filepath.Join(f.Dir, filepath.FromSlash(file))
|
||||
dirpath := filepath.Dir(fp)
|
||||
if dirpath != "." {
|
||||
if err := os.MkdirAll(dirpath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return ioutil.WriteFile(fp, content, 0644)
|
||||
|
||||
}
|
||||
|
||||
// Delete a file at a path
|
||||
func (f *Fake) Delete(file string) error {
|
||||
fp := filepath.Join(f.Dir, filepath.FromSlash(file))
|
||||
return os.RemoveAll(fp)
|
||||
}
|
||||
|
||||
// Close deletes the context
|
||||
func (f *Fake) Close() error {
|
||||
return os.RemoveAll(f.Dir)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package fakestorage
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
@ -6,6 +6,8 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
)
|
||||
|
||||
var ensureHTTPServerOnce sync.Once
|
||||
|
@ -61,7 +63,5 @@ func ensureHTTPServerImage(t testingT) {
|
|||
t.Fatalf("could not build http server: %v", string(out))
|
||||
}
|
||||
|
||||
if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil {
|
||||
t.Fatalf("could not build http server: %v", string(out))
|
||||
}
|
||||
cli.DockerCmd(t, "build", "-q", "-t", "httpserver", tmp)
|
||||
}
|
176
integration-cli/cli/build/fakestorage/storage.go
Normal file
176
integration-cli/cli/build/fakestorage/storage.go
Normal file
|
@ -0,0 +1,176 @@
|
|||
package fakestorage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/integration-cli/environment"
|
||||
"github.com/docker/docker/integration-cli/request"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
)
|
||||
|
||||
var (
|
||||
testEnv *environment.Execution
|
||||
onlyOnce sync.Once
|
||||
)
|
||||
|
||||
// EnsureTestEnvIsLoaded make sure the test environment is loaded for this package
|
||||
func EnsureTestEnvIsLoaded(t testingT) {
|
||||
var doIt bool
|
||||
var err error
|
||||
onlyOnce.Do(func() {
|
||||
doIt = true
|
||||
})
|
||||
|
||||
if !doIt {
|
||||
return
|
||||
}
|
||||
testEnv, err = environment.New()
|
||||
if err != nil {
|
||||
t.Fatalf("error loading testenv : %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type testingT interface {
|
||||
logT
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
type logT interface {
|
||||
Logf(string, ...interface{})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// New returns a static file server that will be use as build context.
|
||||
func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake {
|
||||
ctx := fakecontext.New(t, dir, modifiers...)
|
||||
if testEnv.LocalDaemon() {
|
||||
return newLocalFakeStorage(t, ctx)
|
||||
}
|
||||
return newRemoteFileServer(t, ctx)
|
||||
}
|
||||
|
||||
// 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(t testingT, 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
|
||||
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 := cli.Docker(cli.Args("rmi", "-f", f.image)).Error; err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if f.container == "" {
|
||||
return nil
|
||||
}
|
||||
return cli.Docker(cli.Args("rm", "-fv", f.container)).Error
|
||||
}
|
||||
|
||||
func newRemoteFileServer(t testingT, ctx *fakecontext.Fake) *remoteFileServer {
|
||||
var (
|
||||
image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
|
||||
container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
|
||||
)
|
||||
|
||||
ensureHTTPServerImage(t)
|
||||
|
||||
// Build the image
|
||||
if err := ctx.Add("Dockerfile", `FROM httpserver
|
||||
COPY . /static`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cli.BuildCmd(t, image, build.WithoutCache, build.WithExternalBuildContext(ctx))
|
||||
|
||||
// Start the container
|
||||
cli.DockerCmd(t, "run", "-d", "-P", "--name", container, image)
|
||||
|
||||
// Find out the system assigned port
|
||||
out := cli.DockerCmd(t, "port", container, "80/tcp").Combined()
|
||||
fileserverHostPort := strings.Trim(out, "\n")
|
||||
_, port, err := net.SplitHostPort(fileserverHostPort)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse file server host:port: %v", err)
|
||||
}
|
||||
|
||||
dockerHostURL, err := url.Parse(request.DaemonHost())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse daemon host URL: %v", err)
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(dockerHostURL.Host)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse docker daemon host:port: %v", err)
|
||||
}
|
||||
|
||||
return &remoteFileServer{
|
||||
container: container,
|
||||
image: image,
|
||||
host: fmt.Sprintf("%s:%s", host, port),
|
||||
ctx: ctx}
|
||||
}
|
|
@ -39,6 +39,7 @@ func EnsureTestEnvIsLoaded(t testingT) {
|
|||
type CmdOperator func(*icmd.Cmd) func()
|
||||
|
||||
type testingT interface {
|
||||
Fatal(args ...interface{})
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakestorage"
|
||||
"github.com/docker/docker/integration-cli/request"
|
||||
"github.com/docker/docker/pkg/testutil"
|
||||
"github.com/go-check/check"
|
||||
|
@ -29,7 +31,7 @@ COPY * /tmp/
|
|||
RUN find / -xdev -name ba*
|
||||
RUN find /tmp/`
|
||||
}
|
||||
server := fakeStorage(c, map[string]string{"testD": testD})
|
||||
server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"testD": testD}))
|
||||
defer server.Close()
|
||||
|
||||
res, body, err := request.Post("/build?dockerfile=baz&remote="+server.URL()+"/testD", request.JSON)
|
||||
|
@ -66,9 +68,9 @@ func (s *DockerSuite) TestBuildAPIRemoteTarballContext(c *check.C) {
|
|||
// failed to close tar archive
|
||||
c.Assert(tw.Close(), checker.IsNil)
|
||||
|
||||
server := fakeBinaryStorage(c, map[string]*bytes.Buffer{
|
||||
server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
|
||||
"testT.tar": buffer,
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
res, b, err := request.Post("/build?remote="+server.URL()+"/testT.tar", request.ContentType("application/tar"))
|
||||
|
@ -113,9 +115,9 @@ RUN echo 'right'
|
|||
// failed to close tar archive
|
||||
c.Assert(tw.Close(), checker.IsNil)
|
||||
|
||||
server := fakeBinaryStorage(c, map[string]*bytes.Buffer{
|
||||
server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
|
||||
"testT.tar": buffer,
|
||||
})
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,8 @@ import (
|
|||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/pkg/testutil"
|
||||
icmd "github.com/docker/docker/pkg/testutil/cmd"
|
||||
"github.com/docker/go-units"
|
||||
|
@ -26,10 +28,10 @@ func (s *DockerSuite) TestBuildResourceConstraintsAreUsed(c *check.C) {
|
|||
testRequires(c, cpuCfsQuota)
|
||||
name := "testbuildresourceconstraints"
|
||||
|
||||
ctx := fakeContext(c, `
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`
|
||||
FROM hello-world:frozen
|
||||
RUN ["/hello"]
|
||||
`, map[string]string{})
|
||||
`))
|
||||
cli.Docker(
|
||||
cli.Args("build", "--no-cache", "--rm=false", "--memory=64m", "--memory-swap=-1", "--cpuset-cpus=0", "--cpuset-mems=0", "--cpu-shares=100", "--cpu-quota=8000", "--ulimit", "nofile=42", "-t", name, "."),
|
||||
cli.InDir(ctx.Dir),
|
||||
|
@ -85,7 +87,7 @@ func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) {
|
|||
testRequires(c, DaemonIsLinux)
|
||||
name := "testbuildaddown"
|
||||
|
||||
ctx := func() *FakeContext {
|
||||
ctx := func() *fakecontext.Fake {
|
||||
dockerfile := `
|
||||
FROM busybox
|
||||
ADD foo /bar/
|
||||
|
@ -108,12 +110,12 @@ func (s *DockerSuite) TestBuildAddChangeOwnership(c *check.C) {
|
|||
if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
|
||||
c.Fatalf("failed to open destination dockerfile: %v", err)
|
||||
}
|
||||
return fakeContextFromDir(tmpDir)
|
||||
return fakecontext.New(c, tmpDir)
|
||||
}()
|
||||
|
||||
defer ctx.Close()
|
||||
|
||||
buildImageSuccessfully(c, name, withExternalBuildContext(ctx))
|
||||
buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
|
||||
}
|
||||
|
||||
// Test that an infinite sleep during a build is killed if the client disconnects.
|
||||
|
@ -134,7 +136,7 @@ func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
|
|||
defer observer.Stop()
|
||||
|
||||
// (Note: one year, will never finish)
|
||||
ctx := fakeContext(c, "FROM busybox\nRUN sleep 31536000", nil)
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM busybox\nRUN sleep 31536000"))
|
||||
defer ctx.Close()
|
||||
|
||||
buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
|
||||
|
|
|
@ -10,7 +10,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/testutil"
|
||||
icmd "github.com/docker/docker/pkg/testutil/cmd"
|
||||
|
@ -438,19 +440,21 @@ RUN chmod 755 /entrypoint.sh
|
|||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD echo foobar`
|
||||
|
||||
ctx := fakeContext(c, dockerfile, map[string]string{
|
||||
"entrypoint.sh": `#!/bin/sh
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFiles(map[string]string{
|
||||
"entrypoint.sh": `#!/bin/sh
|
||||
echo "I am an entrypoint"
|
||||
exec "$@"`,
|
||||
})
|
||||
}))
|
||||
defer ctx.Close()
|
||||
|
||||
buildImageSuccessfully(c, name, withExternalBuildContext(ctx))
|
||||
cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
|
||||
|
||||
out, _ := dockerCmd(c, "create", "--entrypoint=", name, "echo", "foo")
|
||||
out := cli.DockerCmd(c, "create", "--entrypoint=", name, "echo", "foo").Combined()
|
||||
id := strings.TrimSpace(out)
|
||||
c.Assert(id, check.Not(check.Equals), "")
|
||||
out, _ = dockerCmd(c, "start", "-a", id)
|
||||
out = cli.DockerCmd(c, "start", "-a", id).Combined()
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "foo")
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
|
@ -4174,22 +4175,25 @@ RUN chmod 755 /entrypoint.sh
|
|||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD echo foobar`
|
||||
|
||||
ctx := fakeContext(c, dockerfile, map[string]string{
|
||||
"entrypoint.sh": `#!/bin/sh
|
||||
ctx := fakecontext.New(c, "",
|
||||
fakecontext.WithDockerfile(dockerfile),
|
||||
fakecontext.WithFiles(map[string]string{
|
||||
"entrypoint.sh": `#!/bin/sh
|
||||
echo "I am an entrypoint"
|
||||
exec "$@"`,
|
||||
})
|
||||
}))
|
||||
defer ctx.Close()
|
||||
|
||||
buildImageSuccessfully(c, name, withExternalBuildContext(ctx))
|
||||
cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--entrypoint=", "-t", name, "echo", "foo")
|
||||
out := cli.DockerCmd(c, "run", "--entrypoint=", "-t", name, "echo", "foo").Combined()
|
||||
c.Assert(strings.TrimSpace(out), check.Equals, "foo")
|
||||
|
||||
// CMD will be reset as well (the same as setting a custom entrypoint)
|
||||
_, _, err := dockerCmdWithError("run", "--entrypoint=", "-t", name)
|
||||
c.Assert(err, check.NotNil)
|
||||
c.Assert(err.Error(), checker.Contains, "No command specified")
|
||||
cli.Docker(cli.Args("run", "--entrypoint=", "-t", name)).Assert(c, icmd.Expected{
|
||||
ExitCode: 125,
|
||||
Err: "No command specified",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *DockerDaemonSuite) TestRunWithUlimitAndDaemonDefault(c *check.C) {
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
@ -22,11 +19,11 @@ import (
|
|||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration-cli/checker"
|
||||
"github.com/docker/docker/integration-cli/cli"
|
||||
"github.com/docker/docker/integration-cli/cli/build"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakecontext"
|
||||
"github.com/docker/docker/integration-cli/cli/build/fakestorage"
|
||||
"github.com/docker/docker/integration-cli/daemon"
|
||||
"github.com/docker/docker/integration-cli/registry"
|
||||
"github.com/docker/docker/integration-cli/request"
|
||||
"github.com/docker/docker/pkg/stringutils"
|
||||
icmd "github.com/docker/docker/pkg/testutil/cmd"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
@ -124,212 +121,6 @@ func getContainerCount(c *check.C) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
// FakeContext creates directories that can be used as a build context
|
||||
type FakeContext struct {
|
||||
Dir string
|
||||
}
|
||||
|
||||
// Add a file at a path, creating directories where necessary
|
||||
func (f *FakeContext) Add(file, content string) error {
|
||||
return f.addFile(file, []byte(content))
|
||||
}
|
||||
|
||||
func (f *FakeContext) addFile(file string, content []byte) error {
|
||||
fp := filepath.Join(f.Dir, filepath.FromSlash(file))
|
||||
dirpath := filepath.Dir(fp)
|
||||
if dirpath != "." {
|
||||
if err := os.MkdirAll(dirpath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return ioutil.WriteFile(fp, content, 0644)
|
||||
|
||||
}
|
||||
|
||||
// Delete a file at a path
|
||||
func (f *FakeContext) Delete(file string) error {
|
||||
fp := filepath.Join(f.Dir, filepath.FromSlash(file))
|
||||
return os.RemoveAll(fp)
|
||||
}
|
||||
|
||||
// Close deletes the context
|
||||
func (f *FakeContext) Close() error {
|
||||
return os.RemoveAll(f.Dir)
|
||||
}
|
||||
|
||||
func fakeContextFromNewTempDir(c *check.C) *FakeContext {
|
||||
tmp, err := ioutil.TempDir("", "fake-context")
|
||||
c.Assert(err, checker.IsNil)
|
||||
if err := os.Chmod(tmp, 0755); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
return fakeContextFromDir(tmp)
|
||||
}
|
||||
|
||||
func fakeContextFromDir(dir string) *FakeContext {
|
||||
return &FakeContext{dir}
|
||||
}
|
||||
|
||||
func fakeContextWithFiles(c *check.C, files map[string]string) *FakeContext {
|
||||
ctx := fakeContextFromNewTempDir(c)
|
||||
for file, content := range files {
|
||||
if err := ctx.Add(file, content); err != nil {
|
||||
ctx.Close()
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
func fakeContextAddDockerfile(c *check.C, ctx *FakeContext, dockerfile string) {
|
||||
if err := ctx.Add("Dockerfile", dockerfile); err != nil {
|
||||
ctx.Close()
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func fakeContext(c *check.C, dockerfile string, files map[string]string) *FakeContext {
|
||||
ctx := fakeContextWithFiles(c, files)
|
||||
fakeContextAddDockerfile(c, ctx, dockerfile)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// FakeStorage is a static file server. It might be running locally or remotely
|
||||
// on test host.
|
||||
type FakeStorage interface {
|
||||
Close() error
|
||||
URL() string
|
||||
CtxDir() string
|
||||
}
|
||||
|
||||
func fakeBinaryStorage(c *check.C, archives map[string]*bytes.Buffer) FakeStorage {
|
||||
ctx := fakeContextFromNewTempDir(c)
|
||||
for name, content := range archives {
|
||||
if err := ctx.addFile(name, content.Bytes()); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
return fakeStorageWithContext(c, ctx)
|
||||
}
|
||||
|
||||
// fakeStorage returns either a local or remote (at daemon machine) file server
|
||||
func fakeStorage(c *check.C, files map[string]string) FakeStorage {
|
||||
ctx := fakeContextWithFiles(c, files)
|
||||
return fakeStorageWithContext(c, ctx)
|
||||
}
|
||||
|
||||
// fakeStorageWithContext returns either a local or remote (at daemon machine) file server
|
||||
func fakeStorageWithContext(c *check.C, ctx *FakeContext) FakeStorage {
|
||||
if testEnv.LocalDaemon() {
|
||||
return newLocalFakeStorage(c, ctx)
|
||||
}
|
||||
return newRemoteFileServer(c, ctx)
|
||||
}
|
||||
|
||||
// localFileStorage is a file storage on the running machine
|
||||
type localFileStorage struct {
|
||||
*FakeContext
|
||||
*httptest.Server
|
||||
}
|
||||
|
||||
func (s *localFileStorage) URL() string {
|
||||
return s.Server.URL
|
||||
}
|
||||
|
||||
func (s *localFileStorage) CtxDir() string {
|
||||
return s.FakeContext.Dir
|
||||
}
|
||||
|
||||
func (s *localFileStorage) Close() error {
|
||||
defer s.Server.Close()
|
||||
return s.FakeContext.Close()
|
||||
}
|
||||
|
||||
func newLocalFakeStorage(c *check.C, ctx *FakeContext) *localFileStorage {
|
||||
handler := http.FileServer(http.Dir(ctx.Dir))
|
||||
server := httptest.NewServer(handler)
|
||||
return &localFileStorage{
|
||||
FakeContext: 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
|
||||
ctx *FakeContext
|
||||
}
|
||||
|
||||
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 != "" {
|
||||
deleteImages(f.image)
|
||||
}
|
||||
}()
|
||||
if f.container == "" {
|
||||
return nil
|
||||
}
|
||||
return deleteContainer(f.container)
|
||||
}
|
||||
|
||||
func newRemoteFileServer(c *check.C, ctx *FakeContext) *remoteFileServer {
|
||||
var (
|
||||
image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
|
||||
container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
|
||||
)
|
||||
|
||||
ensureHTTPServerImage(c)
|
||||
|
||||
// Build the image
|
||||
fakeContextAddDockerfile(c, ctx, `FROM httpserver
|
||||
COPY . /static`)
|
||||
buildImageSuccessfully(c, image, build.WithoutCache, withExternalBuildContext(ctx))
|
||||
|
||||
// Start the container
|
||||
dockerCmd(c, "run", "-d", "-P", "--name", container, image)
|
||||
|
||||
// Find out the system assigned port
|
||||
out, _ := dockerCmd(c, "port", container, "80/tcp")
|
||||
fileserverHostPort := strings.Trim(out, "\n")
|
||||
_, port, err := net.SplitHostPort(fileserverHostPort)
|
||||
if err != nil {
|
||||
c.Fatalf("unable to parse file server host:port: %v", err)
|
||||
}
|
||||
|
||||
dockerHostURL, err := url.Parse(daemonHost())
|
||||
if err != nil {
|
||||
c.Fatalf("unable to parse daemon host URL: %v", err)
|
||||
}
|
||||
|
||||
host, _, err := net.SplitHostPort(dockerHostURL.Host)
|
||||
if err != nil {
|
||||
c.Fatalf("unable to parse docker daemon host:port: %v", err)
|
||||
}
|
||||
|
||||
return &remoteFileServer{
|
||||
container: container,
|
||||
image: image,
|
||||
host: fmt.Sprintf("%s:%s", host, port),
|
||||
ctx: ctx}
|
||||
}
|
||||
|
||||
func inspectFieldAndUnmarshall(c *check.C, name, field string, output interface{}) {
|
||||
str := inspectFieldJSON(c, name, field)
|
||||
err := json.Unmarshal([]byte(str), output)
|
||||
|
@ -452,42 +243,7 @@ func buildImage(name string, cmdOperators ...cli.CmdOperator) *icmd.Result {
|
|||
return cli.Docker(cli.Build(name), cmdOperators...)
|
||||
}
|
||||
|
||||
func withExternalBuildContext(ctx *FakeContext) func(*icmd.Cmd) func() {
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func withBuildContext(c *check.C, contextOperators ...func(*FakeContext) error) func(*icmd.Cmd) func() {
|
||||
ctx := fakeContextFromNewTempDir(c)
|
||||
for _, op := range contextOperators {
|
||||
if err := op(ctx); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
return func(cmd *icmd.Cmd) func() {
|
||||
cmd.Dir = ctx.Dir
|
||||
cmd.Command = append(cmd.Command, ".")
|
||||
return closeBuildContext(c, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func withFile(name, content string) func(*FakeContext) error {
|
||||
return func(ctx *FakeContext) error {
|
||||
return ctx.Add(name, content)
|
||||
}
|
||||
}
|
||||
|
||||
func closeBuildContext(c *check.C, ctx *FakeContext) func() {
|
||||
return func() {
|
||||
if err := ctx.Close(); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: use trustedcmd
|
||||
func trustedBuild(cmd *icmd.Cmd) func() {
|
||||
trustedCmd(cmd)
|
||||
return nil
|
||||
|
@ -523,7 +279,7 @@ func (g *fakeGit) Close() {
|
|||
}
|
||||
|
||||
func newFakeGit(c *check.C, name string, files map[string]string, enforceLocalServer bool) *fakeGit {
|
||||
ctx := fakeContextWithFiles(c, files)
|
||||
ctx := fakecontext.New(c, "", fakecontext.WithFiles(files))
|
||||
defer ctx.Close()
|
||||
curdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
@ -578,7 +334,7 @@ func newFakeGit(c *check.C, name string, files map[string]string, enforceLocalSe
|
|||
var server gitServer
|
||||
if !enforceLocalServer {
|
||||
// use fakeStorage server, which might be local or remote (at test daemon)
|
||||
server = fakeStorageWithContext(c, fakeContextFromDir(root))
|
||||
server = fakestorage.New(c, root)
|
||||
} else {
|
||||
// always start a local http server on CLI test machine
|
||||
httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
|
||||
|
|
|
@ -190,12 +190,6 @@ func (t *testNotary) Close() {
|
|||
os.RemoveAll(t.dir)
|
||||
}
|
||||
|
||||
// Deprecated: used trustedCmd instead
|
||||
func trustedExecCmd(cmd *exec.Cmd) {
|
||||
pwd := "12345678"
|
||||
cmd.Env = append(cmd.Env, trustEnv(notaryURL, pwd, pwd)...)
|
||||
}
|
||||
|
||||
func trustedCmd(cmd *icmd.Cmd) {
|
||||
pwd := "12345678"
|
||||
cmd.Env = append(cmd.Env, trustEnv(notaryURL, pwd, pwd)...)
|
||||
|
|
Loading…
Add table
Reference in a new issue