github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/internal/test/environment/environment.go (about) 1 package environment // import "github.com/docker/docker/internal/test/environment" 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/api/types/filters" 12 "github.com/docker/docker/client" 13 "github.com/docker/docker/internal/test" 14 "github.com/docker/docker/internal/test/fixtures/load" 15 "github.com/pkg/errors" 16 "gotest.tools/assert" 17 ) 18 19 // Execution contains information about the current test execution and daemon 20 // under test 21 type Execution struct { 22 client client.APIClient 23 DaemonInfo types.Info 24 OSType string 25 PlatformDefaults PlatformDefaults 26 protectedElements protectedElements 27 } 28 29 // PlatformDefaults are defaults values for the platform of the daemon under test 30 type PlatformDefaults struct { 31 BaseImage string 32 VolumesConfigPath string 33 ContainerStoragePath string 34 } 35 36 // New creates a new Execution struct 37 func New() (*Execution, error) { 38 client, err := client.NewClientWithOpts(client.FromEnv) 39 if err != nil { 40 return nil, errors.Wrapf(err, "failed to create client") 41 } 42 43 info, err := client.Info(context.Background()) 44 if err != nil { 45 return nil, errors.Wrapf(err, "failed to get info from daemon") 46 } 47 48 osType := getOSType(info) 49 50 return &Execution{ 51 client: client, 52 DaemonInfo: info, 53 OSType: osType, 54 PlatformDefaults: getPlatformDefaults(info, osType), 55 protectedElements: newProtectedElements(), 56 }, nil 57 } 58 59 func getOSType(info types.Info) string { 60 // Docker EE does not set the OSType so allow the user to override this value. 61 userOsType := os.Getenv("TEST_OSTYPE") 62 if userOsType != "" { 63 return userOsType 64 } 65 return info.OSType 66 } 67 68 func getPlatformDefaults(info types.Info, osType string) PlatformDefaults { 69 volumesPath := filepath.Join(info.DockerRootDir, "volumes") 70 containersPath := filepath.Join(info.DockerRootDir, "containers") 71 72 switch osType { 73 case "linux": 74 return PlatformDefaults{ 75 BaseImage: "scratch", 76 VolumesConfigPath: toSlash(volumesPath), 77 ContainerStoragePath: toSlash(containersPath), 78 } 79 case "windows": 80 baseImage := "microsoft/windowsservercore" 81 if override := os.Getenv("WINDOWS_BASE_IMAGE"); override != "" { 82 baseImage = override 83 fmt.Println("INFO: Windows Base image is ", baseImage) 84 } 85 return PlatformDefaults{ 86 BaseImage: baseImage, 87 VolumesConfigPath: filepath.FromSlash(volumesPath), 88 ContainerStoragePath: filepath.FromSlash(containersPath), 89 } 90 default: 91 panic(fmt.Sprintf("unknown OSType for daemon: %s", osType)) 92 } 93 } 94 95 // Make sure in context of daemon, not the local platform. Note we can't 96 // use filepath.FromSlash or ToSlash here as they are a no-op on Unix. 97 func toSlash(path string) string { 98 return strings.Replace(path, `\`, `/`, -1) 99 } 100 101 // IsLocalDaemon is true if the daemon under test is on the same 102 // host as the test process. 103 // 104 // Deterministically working out the environment in which CI is running 105 // to evaluate whether the daemon is local or remote is not possible through 106 // a build tag. 107 // 108 // For example Windows to Linux CI under Jenkins tests the 64-bit 109 // Windows binary build with the daemon build tag, but calls a remote 110 // Linux daemon. 111 // 112 // We can't just say if Windows then assume the daemon is local as at 113 // some point, we will be testing the Windows CLI against a Windows daemon. 114 // 115 // Similarly, it will be perfectly valid to also run CLI tests from 116 // a Linux CLI (built with the daemon tag) against a Windows daemon. 117 func (e *Execution) IsLocalDaemon() bool { 118 return os.Getenv("DOCKER_REMOTE_DAEMON") == "" 119 } 120 121 // IsRemoteDaemon is true if the daemon under test is on different host 122 // as the test process. 123 func (e *Execution) IsRemoteDaemon() bool { 124 return !e.IsLocalDaemon() 125 } 126 127 // DaemonAPIVersion returns the negotiated daemon api version 128 func (e *Execution) DaemonAPIVersion() string { 129 version, err := e.APIClient().ServerVersion(context.TODO()) 130 if err != nil { 131 return "" 132 } 133 return version.APIVersion 134 } 135 136 // Print the execution details to stdout 137 // TODO: print everything 138 func (e *Execution) Print() { 139 if e.IsLocalDaemon() { 140 fmt.Println("INFO: Testing against a local daemon") 141 } else { 142 fmt.Println("INFO: Testing against a remote daemon") 143 } 144 } 145 146 // APIClient returns an APIClient connected to the daemon under test 147 func (e *Execution) APIClient() client.APIClient { 148 return e.client 149 } 150 151 // IsUserNamespace returns whether the user namespace remapping is enabled 152 func (e *Execution) IsUserNamespace() bool { 153 root := os.Getenv("DOCKER_REMAP_ROOT") 154 return root != "" 155 } 156 157 // HasExistingImage checks whether there is an image with the given reference. 158 // Note that this is done by filtering and then checking whether there were any 159 // results -- so ambiguous references might result in false-positives. 160 func (e *Execution) HasExistingImage(t assert.TestingT, reference string) bool { 161 if ht, ok := t.(test.HelperT); ok { 162 ht.Helper() 163 } 164 client := e.APIClient() 165 filter := filters.NewArgs() 166 filter.Add("dangling", "false") 167 filter.Add("reference", reference) 168 imageList, err := client.ImageList(context.Background(), types.ImageListOptions{ 169 All: true, 170 Filters: filter, 171 }) 172 assert.NilError(t, err, "failed to list images") 173 174 return len(imageList) > 0 175 } 176 177 // EnsureFrozenImagesLinux loads frozen test images into the daemon 178 // if they aren't already loaded 179 func EnsureFrozenImagesLinux(testEnv *Execution) error { 180 if testEnv.OSType == "linux" { 181 err := load.FrozenImagesLinux(testEnv.APIClient(), frozenImages...) 182 if err != nil { 183 return errors.Wrap(err, "error loading frozen images") 184 } 185 } 186 return nil 187 }