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