github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration-cli/docker_utils_test.go (about)

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