Tizen_4.0 base
[platform/upstream/docker-engine.git] / integration-cli / cli / build / fakestorage / storage.go
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 }