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