github.com/cookieai-jar/moby@v17.12.1-ce-rc2+incompatible/integration-cli/docker_utils_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "time" 15 16 "github.com/docker/docker/api/types" 17 "github.com/docker/docker/client" 18 "github.com/docker/docker/integration-cli/checker" 19 "github.com/docker/docker/integration-cli/cli" 20 "github.com/docker/docker/integration-cli/daemon" 21 "github.com/docker/docker/integration-cli/registry" 22 "github.com/docker/docker/integration-cli/request" 23 "github.com/go-check/check" 24 "github.com/gotestyourself/gotestyourself/icmd" 25 "golang.org/x/net/context" 26 ) 27 28 // Deprecated 29 func daemonHost() string { 30 return request.DaemonHost() 31 } 32 33 func deleteImages(images ...string) error { 34 args := []string{dockerBinary, "rmi", "-f"} 35 return icmd.RunCmd(icmd.Cmd{Command: append(args, images...)}).Error 36 } 37 38 // Deprecated: use cli.Docker or cli.DockerCmd 39 func dockerCmdWithError(args ...string) (string, int, error) { 40 result := cli.Docker(cli.Args(args...)) 41 if result.Error != nil { 42 return result.Combined(), result.ExitCode, result.Compare(icmd.Success) 43 } 44 return result.Combined(), result.ExitCode, result.Error 45 } 46 47 // Deprecated: use cli.Docker or cli.DockerCmd 48 func dockerCmd(c *check.C, args ...string) (string, int) { 49 result := cli.DockerCmd(c, args...) 50 return result.Combined(), result.ExitCode 51 } 52 53 // Deprecated: use cli.Docker or cli.DockerCmd 54 func dockerCmdWithResult(args ...string) *icmd.Result { 55 return cli.Docker(cli.Args(args...)) 56 } 57 58 func findContainerIP(c *check.C, id string, network string) string { 59 out, _ := dockerCmd(c, "inspect", fmt.Sprintf("--format='{{ .NetworkSettings.Networks.%s.IPAddress }}'", network), id) 60 return strings.Trim(out, " \r\n'") 61 } 62 63 func getContainerCount(c *check.C) int { 64 const containers = "Containers:" 65 66 result := icmd.RunCommand(dockerBinary, "info") 67 result.Assert(c, icmd.Success) 68 69 lines := strings.Split(result.Combined(), "\n") 70 for _, line := range lines { 71 if strings.Contains(line, containers) { 72 output := strings.TrimSpace(line) 73 output = strings.TrimLeft(output, containers) 74 output = strings.Trim(output, " ") 75 containerCount, err := strconv.Atoi(output) 76 c.Assert(err, checker.IsNil) 77 return containerCount 78 } 79 } 80 return 0 81 } 82 83 func inspectFieldAndUnmarshall(c *check.C, name, field string, output interface{}) { 84 str := inspectFieldJSON(c, name, field) 85 err := json.Unmarshal([]byte(str), output) 86 if c != nil { 87 c.Assert(err, check.IsNil, check.Commentf("failed to unmarshal: %v", err)) 88 } 89 } 90 91 // Deprecated: use cli.Inspect 92 func inspectFilter(name, filter string) (string, error) { 93 format := fmt.Sprintf("{{%s}}", filter) 94 result := icmd.RunCommand(dockerBinary, "inspect", "-f", format, name) 95 if result.Error != nil || result.ExitCode != 0 { 96 return "", fmt.Errorf("failed to inspect %s: %s", name, result.Combined()) 97 } 98 return strings.TrimSpace(result.Combined()), nil 99 } 100 101 // Deprecated: use cli.Inspect 102 func inspectFieldWithError(name, field string) (string, error) { 103 return inspectFilter(name, fmt.Sprintf(".%s", field)) 104 } 105 106 // Deprecated: use cli.Inspect 107 func inspectField(c *check.C, name, field string) string { 108 out, err := inspectFilter(name, fmt.Sprintf(".%s", field)) 109 if c != nil { 110 c.Assert(err, check.IsNil) 111 } 112 return out 113 } 114 115 // Deprecated: use cli.Inspect 116 func inspectFieldJSON(c *check.C, name, field string) string { 117 out, err := inspectFilter(name, fmt.Sprintf("json .%s", field)) 118 if c != nil { 119 c.Assert(err, check.IsNil) 120 } 121 return out 122 } 123 124 // Deprecated: use cli.Inspect 125 func inspectFieldMap(c *check.C, name, path, field string) string { 126 out, err := inspectFilter(name, fmt.Sprintf("index .%s %q", path, field)) 127 if c != nil { 128 c.Assert(err, check.IsNil) 129 } 130 return out 131 } 132 133 // Deprecated: use cli.Inspect 134 func inspectMountSourceField(name, destination string) (string, error) { 135 m, err := inspectMountPoint(name, destination) 136 if err != nil { 137 return "", err 138 } 139 return m.Source, nil 140 } 141 142 // Deprecated: use cli.Inspect 143 func inspectMountPoint(name, destination string) (types.MountPoint, error) { 144 out, err := inspectFilter(name, "json .Mounts") 145 if err != nil { 146 return types.MountPoint{}, err 147 } 148 149 return inspectMountPointJSON(out, destination) 150 } 151 152 var errMountNotFound = errors.New("mount point not found") 153 154 // Deprecated: use cli.Inspect 155 func inspectMountPointJSON(j, destination string) (types.MountPoint, error) { 156 var mp []types.MountPoint 157 if err := json.Unmarshal([]byte(j), &mp); err != nil { 158 return types.MountPoint{}, err 159 } 160 161 var m *types.MountPoint 162 for _, c := range mp { 163 if c.Destination == destination { 164 m = &c 165 break 166 } 167 } 168 169 if m == nil { 170 return types.MountPoint{}, errMountNotFound 171 } 172 173 return *m, nil 174 } 175 176 // Deprecated: use cli.Inspect 177 func inspectImage(c *check.C, name, filter string) string { 178 args := []string{"inspect", "--type", "image"} 179 if filter != "" { 180 format := fmt.Sprintf("{{%s}}", filter) 181 args = append(args, "-f", format) 182 } 183 args = append(args, name) 184 result := icmd.RunCommand(dockerBinary, args...) 185 result.Assert(c, icmd.Success) 186 return strings.TrimSpace(result.Combined()) 187 } 188 189 func getIDByName(c *check.C, name string) string { 190 id, err := inspectFieldWithError(name, "Id") 191 c.Assert(err, checker.IsNil) 192 return id 193 } 194 195 // Deprecated: use cli.Build 196 func buildImageSuccessfully(c *check.C, name string, cmdOperators ...cli.CmdOperator) { 197 buildImage(name, cmdOperators...).Assert(c, icmd.Success) 198 } 199 200 // Deprecated: use cli.Build 201 func buildImage(name string, cmdOperators ...cli.CmdOperator) *icmd.Result { 202 return cli.Docker(cli.Build(name), cmdOperators...) 203 } 204 205 // Deprecated: use trustedcmd 206 func trustedBuild(cmd *icmd.Cmd) func() { 207 trustedCmd(cmd) 208 return nil 209 } 210 211 // Write `content` to the file at path `dst`, creating it if necessary, 212 // as well as any missing directories. 213 // The file is truncated if it already exists. 214 // Fail the test when error occurs. 215 func writeFile(dst, content string, c *check.C) { 216 // Create subdirectories if necessary 217 c.Assert(os.MkdirAll(path.Dir(dst), 0700), check.IsNil) 218 f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700) 219 c.Assert(err, check.IsNil) 220 defer f.Close() 221 // Write content (truncate if it exists) 222 _, err = io.Copy(f, strings.NewReader(content)) 223 c.Assert(err, check.IsNil) 224 } 225 226 // Return the contents of file at path `src`. 227 // Fail the test when error occurs. 228 func readFile(src string, c *check.C) (content string) { 229 data, err := ioutil.ReadFile(src) 230 c.Assert(err, check.IsNil) 231 232 return string(data) 233 } 234 235 func containerStorageFile(containerID, basename string) string { 236 return filepath.Join(testEnv.PlatformDefaults.ContainerStoragePath, containerID, basename) 237 } 238 239 // docker commands that use this function must be run with the '-d' switch. 240 func runCommandAndReadContainerFile(c *check.C, filename string, command string, args ...string) []byte { 241 result := icmd.RunCommand(command, args...) 242 result.Assert(c, icmd.Success) 243 contID := strings.TrimSpace(result.Combined()) 244 if err := waitRun(contID); err != nil { 245 c.Fatalf("%v: %q", contID, err) 246 } 247 return readContainerFile(c, contID, filename) 248 } 249 250 func readContainerFile(c *check.C, containerID, filename string) []byte { 251 f, err := os.Open(containerStorageFile(containerID, filename)) 252 c.Assert(err, checker.IsNil) 253 defer f.Close() 254 255 content, err := ioutil.ReadAll(f) 256 c.Assert(err, checker.IsNil) 257 return content 258 } 259 260 func readContainerFileWithExec(c *check.C, containerID, filename string) []byte { 261 result := icmd.RunCommand(dockerBinary, "exec", containerID, "cat", filename) 262 result.Assert(c, icmd.Success) 263 return []byte(result.Combined()) 264 } 265 266 // daemonTime provides the current time on the daemon host 267 func daemonTime(c *check.C) time.Time { 268 if testEnv.IsLocalDaemon() { 269 return time.Now() 270 } 271 cli, err := client.NewEnvClient() 272 c.Assert(err, check.IsNil) 273 defer cli.Close() 274 275 info, err := cli.Info(context.Background()) 276 c.Assert(err, check.IsNil) 277 278 dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) 279 c.Assert(err, check.IsNil, check.Commentf("invalid time format in GET /info response")) 280 return dt 281 } 282 283 // daemonUnixTime returns the current time on the daemon host with nanoseconds precision. 284 // It return the time formatted how the client sends timestamps to the server. 285 func daemonUnixTime(c *check.C) string { 286 return parseEventTime(daemonTime(c)) 287 } 288 289 func parseEventTime(t time.Time) string { 290 return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())) 291 } 292 293 func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 { 294 reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL) 295 c.Assert(err, check.IsNil) 296 297 // Wait for registry to be ready to serve requests. 298 for i := 0; i != 50; i++ { 299 if err = reg.Ping(); err == nil { 300 break 301 } 302 time.Sleep(100 * time.Millisecond) 303 } 304 305 c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err)) 306 return reg 307 } 308 309 func setupNotary(c *check.C) *testNotary { 310 ts, err := newTestNotary(c) 311 c.Assert(err, check.IsNil) 312 313 return ts 314 } 315 316 // appendBaseEnv appends the minimum set of environment variables to exec the 317 // docker cli binary for testing with correct configuration to the given env 318 // list. 319 func appendBaseEnv(isTLS bool, env ...string) []string { 320 preserveList := []string{ 321 // preserve remote test host 322 "DOCKER_HOST", 323 324 // windows: requires preserving SystemRoot, otherwise dial tcp fails 325 // with "GetAddrInfoW: A non-recoverable error occurred during a database lookup." 326 "SystemRoot", 327 328 // testing help text requires the $PATH to dockerd is set 329 "PATH", 330 } 331 if isTLS { 332 preserveList = append(preserveList, "DOCKER_TLS_VERIFY", "DOCKER_CERT_PATH") 333 } 334 335 for _, key := range preserveList { 336 if val := os.Getenv(key); val != "" { 337 env = append(env, fmt.Sprintf("%s=%s", key, val)) 338 } 339 } 340 return env 341 } 342 343 func createTmpFile(c *check.C, content string) string { 344 f, err := ioutil.TempFile("", "testfile") 345 c.Assert(err, check.IsNil) 346 347 filename := f.Name() 348 349 err = ioutil.WriteFile(filename, []byte(content), 0644) 350 c.Assert(err, check.IsNil) 351 352 return filename 353 } 354 355 // waitRun will wait for the specified container to be running, maximum 5 seconds. 356 // Deprecated: use cli.WaitFor 357 func waitRun(contID string) error { 358 return waitInspect(contID, "{{.State.Running}}", "true", 5*time.Second) 359 } 360 361 // waitInspect will wait for the specified container to have the specified string 362 // in the inspect output. It will wait until the specified timeout (in seconds) 363 // is reached. 364 // Deprecated: use cli.WaitFor 365 func waitInspect(name, expr, expected string, timeout time.Duration) error { 366 return waitInspectWithArgs(name, expr, expected, timeout) 367 } 368 369 // Deprecated: use cli.WaitFor 370 func waitInspectWithArgs(name, expr, expected string, timeout time.Duration, arg ...string) error { 371 return daemon.WaitInspectWithArgs(dockerBinary, name, expr, expected, timeout, arg...) 372 } 373 374 func getInspectBody(c *check.C, version, id string) []byte { 375 cli, err := request.NewEnvClientWithVersion(version) 376 c.Assert(err, check.IsNil) 377 defer cli.Close() 378 _, body, err := cli.ContainerInspectWithRaw(context.Background(), id, false) 379 c.Assert(err, check.IsNil) 380 return body 381 } 382 383 // Run a long running idle task in a background container using the 384 // system-specific default image and command. 385 func runSleepingContainer(c *check.C, extraArgs ...string) string { 386 return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...) 387 } 388 389 // Run a long running idle task in a background container using the specified 390 // image and the system-specific command. 391 func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) string { 392 args := []string{"run", "-d"} 393 args = append(args, extraArgs...) 394 args = append(args, image) 395 args = append(args, sleepCommandForDaemonPlatform()...) 396 return strings.TrimSpace(cli.DockerCmd(c, args...).Combined()) 397 } 398 399 // minimalBaseImage returns the name of the minimal base image for the current 400 // daemon platform. 401 func minimalBaseImage() string { 402 return testEnv.MinimalBaseImage() 403 } 404 405 func getGoroutineNumber() (int, error) { 406 cli, err := client.NewEnvClient() 407 if err != nil { 408 return 0, err 409 } 410 defer cli.Close() 411 412 info, err := cli.Info(context.Background()) 413 if err != nil { 414 return 0, err 415 } 416 return info.NGoroutines, nil 417 } 418 419 func waitForGoroutines(expected int) error { 420 t := time.After(30 * time.Second) 421 for { 422 select { 423 case <-t: 424 n, err := getGoroutineNumber() 425 if err != nil { 426 return err 427 } 428 if n > expected { 429 return fmt.Errorf("leaked goroutines: expected less than or equal to %d, got: %d", expected, n) 430 } 431 default: 432 n, err := getGoroutineNumber() 433 if err != nil { 434 return err 435 } 436 if n <= expected { 437 return nil 438 } 439 time.Sleep(200 * time.Millisecond) 440 } 441 } 442 } 443 444 // getErrorMessage returns the error message from an error API response 445 func getErrorMessage(c *check.C, body []byte) string { 446 var resp types.ErrorResponse 447 c.Assert(json.Unmarshal(body, &resp), check.IsNil) 448 return strings.TrimSpace(resp.Message) 449 } 450 451 func waitAndAssert(c *check.C, timeout time.Duration, f checkF, checker check.Checker, args ...interface{}) { 452 after := time.After(timeout) 453 for { 454 v, comment := f(c) 455 assert, _ := checker.Check(append([]interface{}{v}, args...), checker.Info().Params) 456 select { 457 case <-after: 458 assert = true 459 default: 460 } 461 if assert { 462 if comment != nil { 463 args = append(args, comment) 464 } 465 c.Assert(v, checker, args...) 466 return 467 } 468 time.Sleep(100 * time.Millisecond) 469 } 470 } 471 472 type checkF func(*check.C) (interface{}, check.CommentInterface) 473 type reducer func(...interface{}) interface{} 474 475 func reducedCheck(r reducer, funcs ...checkF) checkF { 476 return func(c *check.C) (interface{}, check.CommentInterface) { 477 var values []interface{} 478 var comments []string 479 for _, f := range funcs { 480 v, comment := f(c) 481 values = append(values, v) 482 if comment != nil { 483 comments = append(comments, comment.CheckCommentString()) 484 } 485 } 486 return r(values...), check.Commentf("%v", strings.Join(comments, ", ")) 487 } 488 } 489 490 func sumAsIntegers(vals ...interface{}) interface{} { 491 var s int 492 for _, v := range vals { 493 s += v.(int) 494 } 495 return s 496 }