github.com/ssdev-go/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  }