Tizen_4.0 base
[platform/upstream/docker-engine.git] / integration-cli / environment / environment.go
1 package environment
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "os"
7         "os/exec"
8         "path/filepath"
9         "strconv"
10         "strings"
11
12         "github.com/docker/docker/api/types"
13         "github.com/docker/docker/api/types/container"
14         "github.com/docker/docker/client"
15         "github.com/docker/docker/opts"
16         "golang.org/x/net/context"
17 )
18
19 var (
20         // DefaultClientBinary is the name of the docker binary
21         DefaultClientBinary = os.Getenv("TEST_CLIENT_BINARY")
22 )
23
24 func init() {
25         if DefaultClientBinary == "" {
26                 // TODO: to be removed once we no longer depend on the docker cli for integration tests
27                 //panic("TEST_CLIENT_BINARY must be set")
28                 DefaultClientBinary = "docker"
29         }
30 }
31
32 // Execution holds informations about the test execution environment.
33 type Execution struct {
34         daemonPlatform      string
35         localDaemon         bool
36         experimentalDaemon  bool
37         daemonStorageDriver string
38         isolation           container.Isolation
39         daemonPid           int
40         daemonKernelVersion string
41         // For a local daemon on Linux, these values will be used for testing
42         // user namespace support as the standard graph path(s) will be
43         // appended with the root remapped uid.gid prefix
44         dockerBasePath       string
45         volumesConfigPath    string
46         containerStoragePath string
47         // baseImage is the name of the base image for testing
48         // Environment variable WINDOWS_BASE_IMAGE can override this
49         baseImage    string
50         dockerBinary string
51
52         protectedElements protectedElements
53 }
54
55 // New creates a new Execution struct
56 func New() (*Execution, error) {
57         localDaemon := true
58         // Deterministically working out the environment in which CI is running
59         // to evaluate whether the daemon is local or remote is not possible through
60         // a build tag.
61         //
62         // For example Windows to Linux CI under Jenkins tests the 64-bit
63         // Windows binary build with the daemon build tag, but calls a remote
64         // Linux daemon.
65         //
66         // We can't just say if Windows then assume the daemon is local as at
67         // some point, we will be testing the Windows CLI against a Windows daemon.
68         //
69         // Similarly, it will be perfectly valid to also run CLI tests from
70         // a Linux CLI (built with the daemon tag) against a Windows daemon.
71         if len(os.Getenv("DOCKER_REMOTE_DAEMON")) > 0 {
72                 localDaemon = false
73         }
74         info, err := getDaemonDockerInfo()
75         if err != nil {
76                 return nil, err
77         }
78         daemonPlatform := info.OSType
79         if daemonPlatform != "linux" && daemonPlatform != "windows" {
80                 return nil, fmt.Errorf("Cannot run tests against platform: %s", daemonPlatform)
81         }
82         baseImage := "scratch"
83         volumesConfigPath := filepath.Join(info.DockerRootDir, "volumes")
84         containerStoragePath := filepath.Join(info.DockerRootDir, "containers")
85         // Make sure in context of daemon, not the local platform. Note we can't
86         // use filepath.FromSlash or ToSlash here as they are a no-op on Unix.
87         if daemonPlatform == "windows" {
88                 volumesConfigPath = strings.Replace(volumesConfigPath, `/`, `\`, -1)
89                 containerStoragePath = strings.Replace(containerStoragePath, `/`, `\`, -1)
90
91                 baseImage = "microsoft/windowsservercore"
92                 if len(os.Getenv("WINDOWS_BASE_IMAGE")) > 0 {
93                         baseImage = os.Getenv("WINDOWS_BASE_IMAGE")
94                         fmt.Println("INFO: Windows Base image is ", baseImage)
95                 }
96         } else {
97                 volumesConfigPath = strings.Replace(volumesConfigPath, `\`, `/`, -1)
98                 containerStoragePath = strings.Replace(containerStoragePath, `\`, `/`, -1)
99         }
100
101         var daemonPid int
102         dest := os.Getenv("DEST")
103         b, err := ioutil.ReadFile(filepath.Join(dest, "docker.pid"))
104         if err == nil {
105                 if p, err := strconv.ParseInt(string(b), 10, 32); err == nil {
106                         daemonPid = int(p)
107                 }
108         }
109
110         dockerBinary, err := exec.LookPath(DefaultClientBinary)
111         if err != nil {
112                 return nil, err
113         }
114
115         return &Execution{
116                 localDaemon:          localDaemon,
117                 daemonPlatform:       daemonPlatform,
118                 daemonStorageDriver:  info.Driver,
119                 daemonKernelVersion:  info.KernelVersion,
120                 dockerBasePath:       info.DockerRootDir,
121                 volumesConfigPath:    volumesConfigPath,
122                 containerStoragePath: containerStoragePath,
123                 isolation:            info.Isolation,
124                 daemonPid:            daemonPid,
125                 experimentalDaemon:   info.ExperimentalBuild,
126                 baseImage:            baseImage,
127                 dockerBinary:         dockerBinary,
128                 protectedElements: protectedElements{
129                         images: map[string]struct{}{},
130                 },
131         }, nil
132 }
133 func getDaemonDockerInfo() (types.Info, error) {
134         // FIXME(vdemeester) should be safe to use as is
135         client, err := client.NewEnvClient()
136         if err != nil {
137                 return types.Info{}, err
138         }
139         return client.Info(context.Background())
140 }
141
142 // LocalDaemon is true if the daemon under test is on the same
143 // host as the CLI.
144 func (e *Execution) LocalDaemon() bool {
145         return e.localDaemon
146 }
147
148 // DaemonPlatform is held globally so that tests can make intelligent
149 // decisions on how to configure themselves according to the platform
150 // of the daemon. This is initialized in docker_utils by sending
151 // a version call to the daemon and examining the response header.
152 func (e *Execution) DaemonPlatform() string {
153         return e.daemonPlatform
154 }
155
156 // DockerBasePath is the base path of the docker folder (by default it is -/var/run/docker)
157 func (e *Execution) DockerBasePath() string {
158         return e.dockerBasePath
159 }
160
161 // VolumesConfigPath is the path of the volume configuration for the testing daemon
162 func (e *Execution) VolumesConfigPath() string {
163         return e.volumesConfigPath
164 }
165
166 // ContainerStoragePath is the path where the container are stored for the testing daemon
167 func (e *Execution) ContainerStoragePath() string {
168         return e.containerStoragePath
169 }
170
171 // DaemonStorageDriver is held globally so that tests can know the storage
172 // driver of the daemon. This is initialized in docker_utils by sending
173 // a version call to the daemon and examining the response header.
174 func (e *Execution) DaemonStorageDriver() string {
175         return e.daemonStorageDriver
176 }
177
178 // Isolation is the isolation mode of the daemon under test
179 func (e *Execution) Isolation() container.Isolation {
180         return e.isolation
181 }
182
183 // DaemonPID is the pid of the main test daemon
184 func (e *Execution) DaemonPID() int {
185         return e.daemonPid
186 }
187
188 // ExperimentalDaemon tell whether the main daemon has
189 // experimental features enabled or not
190 func (e *Execution) ExperimentalDaemon() bool {
191         return e.experimentalDaemon
192 }
193
194 // MinimalBaseImage is the image used for minimal builds (it depends on the platform)
195 func (e *Execution) MinimalBaseImage() string {
196         return e.baseImage
197 }
198
199 // DaemonKernelVersion is the kernel version of the daemon as a string, as returned
200 // by an INFO call to the daemon.
201 func (e *Execution) DaemonKernelVersion() string {
202         return e.daemonKernelVersion
203 }
204
205 // DaemonKernelVersionNumeric is the kernel version of the daemon as an integer.
206 // Mostly useful on Windows where DaemonKernelVersion holds the full string such
207 // as `10.0 14393 (14393.447.amd64fre.rs1_release_inmarket.161102-0100)`, but
208 // integration tests really only need the `14393` piece to make decisions.
209 func (e *Execution) DaemonKernelVersionNumeric() int {
210         if e.daemonPlatform != "windows" {
211                 return -1
212         }
213         v, _ := strconv.Atoi(strings.Split(e.daemonKernelVersion, " ")[1])
214         return v
215 }
216
217 // DockerBinary returns the docker binary for this testing environment
218 func (e *Execution) DockerBinary() string {
219         return e.dockerBinary
220 }
221
222 // DaemonHost return the daemon host string for this test execution
223 func DaemonHost() string {
224         daemonURLStr := "unix://" + opts.DefaultUnixSocket
225         if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
226                 daemonURLStr = daemonHostVar
227         }
228         return daemonURLStr
229 }