github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/integration-cli/cli/build/fakestorage/storage.go (about) 1 package fakestorage 2 3 import ( 4 "fmt" 5 "net" 6 "net/http" 7 "net/http/httptest" 8 "net/url" 9 "os" 10 "strings" 11 12 "github.com/docker/docker/integration-cli/cli" 13 "github.com/docker/docker/integration-cli/cli/build" 14 "github.com/docker/docker/integration-cli/cli/build/fakecontext" 15 "github.com/docker/docker/integration-cli/request" 16 "github.com/docker/docker/internal/test/environment" 17 "github.com/docker/docker/internal/testutil" 18 "github.com/stretchr/testify/require" 19 ) 20 21 var testEnv *environment.Execution 22 23 type testingT interface { 24 require.TestingT 25 logT 26 Fatal(args ...interface{}) 27 Fatalf(string, ...interface{}) 28 } 29 30 type logT interface { 31 Logf(string, ...interface{}) 32 } 33 34 // Fake is a static file server. It might be running locally or remotely 35 // on test host. 36 type Fake interface { 37 Close() error 38 URL() string 39 CtxDir() string 40 } 41 42 // SetTestEnvironment sets a static test environment 43 // TODO: decouple this package from environment 44 func SetTestEnvironment(env *environment.Execution) { 45 testEnv = env 46 } 47 48 // New returns a static file server that will be use as build context. 49 func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake { 50 if testEnv == nil { 51 t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.") 52 } 53 ctx := fakecontext.New(t, dir, modifiers...) 54 if testEnv.IsLocalDaemon() { 55 return newLocalFakeStorage(ctx) 56 } 57 return newRemoteFileServer(t, ctx) 58 } 59 60 // localFileStorage is a file storage on the running machine 61 type localFileStorage struct { 62 *fakecontext.Fake 63 *httptest.Server 64 } 65 66 func (s *localFileStorage) URL() string { 67 return s.Server.URL 68 } 69 70 func (s *localFileStorage) CtxDir() string { 71 return s.Fake.Dir 72 } 73 74 func (s *localFileStorage) Close() error { 75 defer s.Server.Close() 76 return s.Fake.Close() 77 } 78 79 func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage { 80 handler := http.FileServer(http.Dir(ctx.Dir)) 81 server := httptest.NewServer(handler) 82 return &localFileStorage{ 83 Fake: ctx, 84 Server: server, 85 } 86 } 87 88 // remoteFileServer is a containerized static file server started on the remote 89 // testing machine to be used in URL-accepting docker build functionality. 90 type remoteFileServer struct { 91 host string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712 92 container string 93 image string 94 ctx *fakecontext.Fake 95 } 96 97 func (f *remoteFileServer) URL() string { 98 u := url.URL{ 99 Scheme: "http", 100 Host: f.host} 101 return u.String() 102 } 103 104 func (f *remoteFileServer) CtxDir() string { 105 return f.ctx.Dir 106 } 107 108 func (f *remoteFileServer) Close() error { 109 defer func() { 110 if f.ctx != nil { 111 f.ctx.Close() 112 } 113 if f.image != "" { 114 if err := cli.Docker(cli.Args("rmi", "-f", f.image)).Error; err != nil { 115 fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err) 116 } 117 } 118 }() 119 if f.container == "" { 120 return nil 121 } 122 return cli.Docker(cli.Args("rm", "-fv", f.container)).Error 123 } 124 125 func newRemoteFileServer(t testingT, ctx *fakecontext.Fake) *remoteFileServer { 126 var ( 127 image = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10))) 128 container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10))) 129 ) 130 131 ensureHTTPServerImage(t) 132 133 // Build the image 134 if err := ctx.Add("Dockerfile", `FROM httpserver 135 COPY . /static`); err != nil { 136 t.Fatal(err) 137 } 138 cli.BuildCmd(t, image, build.WithoutCache, build.WithExternalBuildContext(ctx)) 139 140 // Start the container 141 cli.DockerCmd(t, "run", "-d", "-P", "--name", container, image) 142 143 // Find out the system assigned port 144 out := cli.DockerCmd(t, "port", container, "80/tcp").Combined() 145 fileserverHostPort := strings.Trim(out, "\n") 146 _, port, err := net.SplitHostPort(fileserverHostPort) 147 if err != nil { 148 t.Fatalf("unable to parse file server host:port: %v", err) 149 } 150 151 dockerHostURL, err := url.Parse(request.DaemonHost()) 152 if err != nil { 153 t.Fatalf("unable to parse daemon host URL: %v", err) 154 } 155 156 host, _, err := net.SplitHostPort(dockerHostURL.Host) 157 if err != nil { 158 t.Fatalf("unable to parse docker daemon host:port: %v", err) 159 } 160 161 return &remoteFileServer{ 162 container: container, 163 image: image, 164 host: fmt.Sprintf("%s:%s", host, port), 165 ctx: ctx} 166 }