github.com/michael-k/docker@v1.7.0-rc2/integration-cli/docker_utils.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"net"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"net/http/httputil"
    14  	"net/url"
    15  	"os"
    16  	"os/exec"
    17  	"path"
    18  	"path/filepath"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/docker/docker/opts"
    24  	"github.com/docker/docker/pkg/ioutils"
    25  	"github.com/docker/docker/pkg/stringutils"
    26  	"github.com/go-check/check"
    27  )
    28  
    29  // Daemon represents a Docker daemon for the testing framework.
    30  type Daemon struct {
    31  	c              *check.C
    32  	logFile        *os.File
    33  	folder         string
    34  	stdin          io.WriteCloser
    35  	stdout, stderr io.ReadCloser
    36  	cmd            *exec.Cmd
    37  	storageDriver  string
    38  	execDriver     string
    39  	wait           chan error
    40  	userlandProxy  bool
    41  }
    42  
    43  func enableUserlandProxy() bool {
    44  	if env := os.Getenv("DOCKER_USERLANDPROXY"); env != "" {
    45  		if val, err := strconv.ParseBool(env); err != nil {
    46  			return val
    47  		}
    48  	}
    49  	return true
    50  }
    51  
    52  // NewDaemon returns a Daemon instance to be used for testing.
    53  // This will create a directory such as daemon123456789 in the folder specified by $DEST.
    54  // The daemon will not automatically start.
    55  func NewDaemon(c *check.C) *Daemon {
    56  	dest := os.Getenv("DEST")
    57  	if dest == "" {
    58  		c.Fatal("Please set the DEST environment variable")
    59  	}
    60  
    61  	dir := filepath.Join(dest, fmt.Sprintf("d%d", time.Now().UnixNano()%100000000))
    62  	daemonFolder, err := filepath.Abs(dir)
    63  	if err != nil {
    64  		c.Fatalf("Could not make %q an absolute path: %v", dir, err)
    65  	}
    66  
    67  	if err := os.MkdirAll(filepath.Join(daemonFolder, "graph"), 0600); err != nil {
    68  		c.Fatalf("Could not create %s/graph directory", daemonFolder)
    69  	}
    70  
    71  	userlandProxy := true
    72  	if env := os.Getenv("DOCKER_USERLANDPROXY"); env != "" {
    73  		if val, err := strconv.ParseBool(env); err != nil {
    74  			userlandProxy = val
    75  		}
    76  	}
    77  
    78  	return &Daemon{
    79  		c:             c,
    80  		folder:        daemonFolder,
    81  		storageDriver: os.Getenv("DOCKER_GRAPHDRIVER"),
    82  		execDriver:    os.Getenv("DOCKER_EXECDRIVER"),
    83  		userlandProxy: userlandProxy,
    84  	}
    85  }
    86  
    87  // Start will start the daemon and return once it is ready to receive requests.
    88  // You can specify additional daemon flags.
    89  func (d *Daemon) Start(arg ...string) error {
    90  	dockerBinary, err := exec.LookPath(dockerBinary)
    91  	if err != nil {
    92  		d.c.Fatalf("could not find docker binary in $PATH: %v", err)
    93  	}
    94  
    95  	args := []string{
    96  		"--host", d.sock(),
    97  		"--daemon",
    98  		"--graph", fmt.Sprintf("%s/graph", d.folder),
    99  		"--pidfile", fmt.Sprintf("%s/docker.pid", d.folder),
   100  		fmt.Sprintf("--userland-proxy=%t", d.userlandProxy),
   101  	}
   102  
   103  	// If we don't explicitly set the log-level or debug flag(-D) then
   104  	// turn on debug mode
   105  	foundIt := false
   106  	for _, a := range arg {
   107  		if strings.Contains(a, "--log-level") || strings.Contains(a, "-D") {
   108  			foundIt = true
   109  		}
   110  	}
   111  	if !foundIt {
   112  		args = append(args, "--debug")
   113  	}
   114  
   115  	if d.storageDriver != "" {
   116  		args = append(args, "--storage-driver", d.storageDriver)
   117  	}
   118  	if d.execDriver != "" {
   119  		args = append(args, "--exec-driver", d.execDriver)
   120  	}
   121  
   122  	args = append(args, arg...)
   123  	d.cmd = exec.Command(dockerBinary, args...)
   124  
   125  	d.logFile, err = os.OpenFile(filepath.Join(d.folder, "docker.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
   126  	if err != nil {
   127  		d.c.Fatalf("Could not create %s/docker.log: %v", d.folder, err)
   128  	}
   129  
   130  	d.cmd.Stdout = d.logFile
   131  	d.cmd.Stderr = d.logFile
   132  
   133  	if err := d.cmd.Start(); err != nil {
   134  		return fmt.Errorf("could not start daemon container: %v", err)
   135  	}
   136  
   137  	wait := make(chan error)
   138  
   139  	go func() {
   140  		wait <- d.cmd.Wait()
   141  		d.c.Log("exiting daemon")
   142  		close(wait)
   143  	}()
   144  
   145  	d.wait = wait
   146  
   147  	tick := time.Tick(500 * time.Millisecond)
   148  	// make sure daemon is ready to receive requests
   149  	startTime := time.Now().Unix()
   150  	for {
   151  		d.c.Log("waiting for daemon to start")
   152  		if time.Now().Unix()-startTime > 5 {
   153  			// After 5 seconds, give up
   154  			return errors.New("Daemon exited and never started")
   155  		}
   156  		select {
   157  		case <-time.After(2 * time.Second):
   158  			return errors.New("timeout: daemon does not respond")
   159  		case <-tick:
   160  			c, err := net.Dial("unix", filepath.Join(d.folder, "docker.sock"))
   161  			if err != nil {
   162  				continue
   163  			}
   164  
   165  			client := httputil.NewClientConn(c, nil)
   166  			defer client.Close()
   167  
   168  			req, err := http.NewRequest("GET", "/_ping", nil)
   169  			if err != nil {
   170  				d.c.Fatalf("could not create new request: %v", err)
   171  			}
   172  
   173  			resp, err := client.Do(req)
   174  			if err != nil {
   175  				continue
   176  			}
   177  			if resp.StatusCode != http.StatusOK {
   178  				d.c.Logf("received status != 200 OK: %s", resp.Status)
   179  			}
   180  
   181  			d.c.Log("daemon started")
   182  			return nil
   183  		}
   184  	}
   185  }
   186  
   187  // StartWithBusybox will first start the daemon with Daemon.Start()
   188  // then save the busybox image from the main daemon and load it into this Daemon instance.
   189  func (d *Daemon) StartWithBusybox(arg ...string) error {
   190  	if err := d.Start(arg...); err != nil {
   191  		return err
   192  	}
   193  	bb := filepath.Join(d.folder, "busybox.tar")
   194  	if _, err := os.Stat(bb); err != nil {
   195  		if !os.IsNotExist(err) {
   196  			return fmt.Errorf("unexpected error on busybox.tar stat: %v", err)
   197  		}
   198  		// saving busybox image from main daemon
   199  		if err := exec.Command(dockerBinary, "save", "--output", bb, "busybox:latest").Run(); err != nil {
   200  			return fmt.Errorf("could not save busybox image: %v", err)
   201  		}
   202  	}
   203  	// loading busybox image to this daemon
   204  	if _, err := d.Cmd("load", "--input", bb); err != nil {
   205  		return fmt.Errorf("could not load busybox image: %v", err)
   206  	}
   207  	if err := os.Remove(bb); err != nil {
   208  		d.c.Logf("Could not remove %s: %v", bb, err)
   209  	}
   210  	return nil
   211  }
   212  
   213  // Stop will send a SIGINT every second and wait for the daemon to stop.
   214  // If it timeouts, a SIGKILL is sent.
   215  // Stop will not delete the daemon directory. If a purged daemon is needed,
   216  // instantiate a new one with NewDaemon.
   217  func (d *Daemon) Stop() error {
   218  	if d.cmd == nil || d.wait == nil {
   219  		return errors.New("daemon not started")
   220  	}
   221  
   222  	defer func() {
   223  		d.logFile.Close()
   224  		d.cmd = nil
   225  	}()
   226  
   227  	i := 1
   228  	tick := time.Tick(time.Second)
   229  
   230  	if err := d.cmd.Process.Signal(os.Interrupt); err != nil {
   231  		return fmt.Errorf("could not send signal: %v", err)
   232  	}
   233  out1:
   234  	for {
   235  		select {
   236  		case err := <-d.wait:
   237  			return err
   238  		case <-time.After(15 * time.Second):
   239  			// time for stopping jobs and run onShutdown hooks
   240  			d.c.Log("timeout")
   241  			break out1
   242  		}
   243  	}
   244  
   245  out2:
   246  	for {
   247  		select {
   248  		case err := <-d.wait:
   249  			return err
   250  		case <-tick:
   251  			i++
   252  			if i > 4 {
   253  				d.c.Logf("tried to interrupt daemon for %d times, now try to kill it", i)
   254  				break out2
   255  			}
   256  			d.c.Logf("Attempt #%d: daemon is still running with pid %d", i, d.cmd.Process.Pid)
   257  			if err := d.cmd.Process.Signal(os.Interrupt); err != nil {
   258  				return fmt.Errorf("could not send signal: %v", err)
   259  			}
   260  		}
   261  	}
   262  
   263  	if err := d.cmd.Process.Kill(); err != nil {
   264  		d.c.Logf("Could not kill daemon: %v", err)
   265  		return err
   266  	}
   267  
   268  	return nil
   269  }
   270  
   271  // Restart will restart the daemon by first stopping it and then starting it.
   272  func (d *Daemon) Restart(arg ...string) error {
   273  	d.Stop()
   274  	return d.Start(arg...)
   275  }
   276  
   277  func (d *Daemon) sock() string {
   278  	return fmt.Sprintf("unix://%s/docker.sock", d.folder)
   279  }
   280  
   281  // Cmd will execute a docker CLI command against this Daemon.
   282  // Example: d.Cmd("version") will run docker -H unix://path/to/unix.sock version
   283  func (d *Daemon) Cmd(name string, arg ...string) (string, error) {
   284  	args := []string{"--host", d.sock(), name}
   285  	args = append(args, arg...)
   286  	c := exec.Command(dockerBinary, args...)
   287  	b, err := c.CombinedOutput()
   288  	return string(b), err
   289  }
   290  
   291  func (d *Daemon) CmdWithArgs(daemonArgs []string, name string, arg ...string) (string, error) {
   292  	args := append(daemonArgs, name)
   293  	args = append(args, arg...)
   294  	c := exec.Command(dockerBinary, args...)
   295  	b, err := c.CombinedOutput()
   296  	return string(b), err
   297  }
   298  
   299  func (d *Daemon) LogfileName() string {
   300  	return d.logFile.Name()
   301  }
   302  
   303  func daemonHost() string {
   304  	daemonUrlStr := "unix://" + opts.DefaultUnixSocket
   305  	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
   306  		daemonUrlStr = daemonHostVar
   307  	}
   308  	return daemonUrlStr
   309  }
   310  
   311  func sockConn(timeout time.Duration) (net.Conn, error) {
   312  	daemon := daemonHost()
   313  	daemonUrl, err := url.Parse(daemon)
   314  	if err != nil {
   315  		return nil, fmt.Errorf("could not parse url %q: %v", daemon, err)
   316  	}
   317  
   318  	var c net.Conn
   319  	switch daemonUrl.Scheme {
   320  	case "unix":
   321  		return net.DialTimeout(daemonUrl.Scheme, daemonUrl.Path, timeout)
   322  	case "tcp":
   323  		return net.DialTimeout(daemonUrl.Scheme, daemonUrl.Host, timeout)
   324  	default:
   325  		return c, fmt.Errorf("unknown scheme %v (%s)", daemonUrl.Scheme, daemon)
   326  	}
   327  }
   328  
   329  func sockRequest(method, endpoint string, data interface{}) (int, []byte, error) {
   330  	jsonData := bytes.NewBuffer(nil)
   331  	if err := json.NewEncoder(jsonData).Encode(data); err != nil {
   332  		return -1, nil, err
   333  	}
   334  
   335  	res, body, err := sockRequestRaw(method, endpoint, jsonData, "application/json")
   336  	if err != nil {
   337  		b, _ := ioutil.ReadAll(body)
   338  		return -1, b, err
   339  	}
   340  	var b []byte
   341  	b, err = readBody(body)
   342  	return res.StatusCode, b, err
   343  }
   344  
   345  func sockRequestRaw(method, endpoint string, data io.Reader, ct string) (*http.Response, io.ReadCloser, error) {
   346  	c, err := sockConn(time.Duration(10 * time.Second))
   347  	if err != nil {
   348  		return nil, nil, fmt.Errorf("could not dial docker daemon: %v", err)
   349  	}
   350  
   351  	client := httputil.NewClientConn(c, nil)
   352  
   353  	req, err := http.NewRequest(method, endpoint, data)
   354  	if err != nil {
   355  		client.Close()
   356  		return nil, nil, fmt.Errorf("could not create new request: %v", err)
   357  	}
   358  
   359  	if ct != "" {
   360  		req.Header.Set("Content-Type", ct)
   361  	}
   362  
   363  	resp, err := client.Do(req)
   364  	if err != nil {
   365  		client.Close()
   366  		return nil, nil, fmt.Errorf("could not perform request: %v", err)
   367  	}
   368  	body := ioutils.NewReadCloserWrapper(resp.Body, func() error {
   369  		defer client.Close()
   370  		return resp.Body.Close()
   371  	})
   372  
   373  	return resp, body, nil
   374  }
   375  
   376  func readBody(b io.ReadCloser) ([]byte, error) {
   377  	defer b.Close()
   378  	return ioutil.ReadAll(b)
   379  }
   380  
   381  func deleteContainer(container string) error {
   382  	container = strings.TrimSpace(strings.Replace(container, "\n", " ", -1))
   383  	rmArgs := strings.Split(fmt.Sprintf("rm -fv %v", container), " ")
   384  	exitCode, err := runCommand(exec.Command(dockerBinary, rmArgs...))
   385  	// set error manually if not set
   386  	if exitCode != 0 && err == nil {
   387  		err = fmt.Errorf("failed to remove container: `docker rm` exit is non-zero")
   388  	}
   389  
   390  	return err
   391  }
   392  
   393  func getAllContainers() (string, error) {
   394  	getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
   395  	out, exitCode, err := runCommandWithOutput(getContainersCmd)
   396  	if exitCode != 0 && err == nil {
   397  		err = fmt.Errorf("failed to get a list of containers: %v\n", out)
   398  	}
   399  
   400  	return out, err
   401  }
   402  
   403  func deleteAllContainers() error {
   404  	containers, err := getAllContainers()
   405  	if err != nil {
   406  		fmt.Println(containers)
   407  		return err
   408  	}
   409  
   410  	if err = deleteContainer(containers); err != nil {
   411  		return err
   412  	}
   413  	return nil
   414  }
   415  
   416  var protectedImages = map[string]struct{}{}
   417  
   418  func init() {
   419  	out, err := exec.Command(dockerBinary, "images").CombinedOutput()
   420  	if err != nil {
   421  		panic(err)
   422  	}
   423  	lines := strings.Split(string(out), "\n")[1:]
   424  	for _, l := range lines {
   425  		if l == "" {
   426  			continue
   427  		}
   428  		fields := strings.Fields(l)
   429  		imgTag := fields[0] + ":" + fields[1]
   430  		// just for case if we have dangling images in tested daemon
   431  		if imgTag != "<none>:<none>" {
   432  			protectedImages[imgTag] = struct{}{}
   433  		}
   434  	}
   435  }
   436  
   437  func deleteAllImages() error {
   438  	out, err := exec.Command(dockerBinary, "images").CombinedOutput()
   439  	if err != nil {
   440  		return err
   441  	}
   442  	lines := strings.Split(string(out), "\n")[1:]
   443  	var imgs []string
   444  	for _, l := range lines {
   445  		if l == "" {
   446  			continue
   447  		}
   448  		fields := strings.Fields(l)
   449  		imgTag := fields[0] + ":" + fields[1]
   450  		if _, ok := protectedImages[imgTag]; !ok {
   451  			if fields[0] == "<none>" {
   452  				imgs = append(imgs, fields[2])
   453  				continue
   454  			}
   455  			imgs = append(imgs, imgTag)
   456  		}
   457  	}
   458  	if len(imgs) == 0 {
   459  		return nil
   460  	}
   461  	args := append([]string{"rmi", "-f"}, imgs...)
   462  	if err := exec.Command(dockerBinary, args...).Run(); err != nil {
   463  		return err
   464  	}
   465  	return nil
   466  }
   467  
   468  func getPausedContainers() (string, error) {
   469  	getPausedContainersCmd := exec.Command(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
   470  	out, exitCode, err := runCommandWithOutput(getPausedContainersCmd)
   471  	if exitCode != 0 && err == nil {
   472  		err = fmt.Errorf("failed to get a list of paused containers: %v\n", out)
   473  	}
   474  
   475  	return out, err
   476  }
   477  
   478  func getSliceOfPausedContainers() ([]string, error) {
   479  	out, err := getPausedContainers()
   480  	if err == nil {
   481  		if len(out) == 0 {
   482  			return nil, err
   483  		}
   484  		slice := strings.Split(strings.TrimSpace(out), "\n")
   485  		return slice, err
   486  	}
   487  	return []string{out}, err
   488  }
   489  
   490  func unpauseContainer(container string) error {
   491  	unpauseCmd := exec.Command(dockerBinary, "unpause", container)
   492  	exitCode, err := runCommand(unpauseCmd)
   493  	if exitCode != 0 && err == nil {
   494  		err = fmt.Errorf("failed to unpause container")
   495  	}
   496  
   497  	return nil
   498  }
   499  
   500  func unpauseAllContainers() error {
   501  	containers, err := getPausedContainers()
   502  	if err != nil {
   503  		fmt.Println(containers)
   504  		return err
   505  	}
   506  
   507  	containers = strings.Replace(containers, "\n", " ", -1)
   508  	containers = strings.Trim(containers, " ")
   509  	containerList := strings.Split(containers, " ")
   510  
   511  	for _, value := range containerList {
   512  		if err = unpauseContainer(value); err != nil {
   513  			return err
   514  		}
   515  	}
   516  
   517  	return nil
   518  }
   519  
   520  func deleteImages(images ...string) error {
   521  	args := []string{"rmi", "-f"}
   522  	args = append(args, images...)
   523  	rmiCmd := exec.Command(dockerBinary, args...)
   524  	exitCode, err := runCommand(rmiCmd)
   525  	// set error manually if not set
   526  	if exitCode != 0 && err == nil {
   527  		err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
   528  	}
   529  	return err
   530  }
   531  
   532  func imageExists(image string) error {
   533  	inspectCmd := exec.Command(dockerBinary, "inspect", image)
   534  	exitCode, err := runCommand(inspectCmd)
   535  	if exitCode != 0 && err == nil {
   536  		err = fmt.Errorf("couldn't find image %q", image)
   537  	}
   538  	return err
   539  }
   540  
   541  func pullImageIfNotExist(image string) (err error) {
   542  	if err := imageExists(image); err != nil {
   543  		pullCmd := exec.Command(dockerBinary, "pull", image)
   544  		_, exitCode, err := runCommandWithOutput(pullCmd)
   545  
   546  		if err != nil || exitCode != 0 {
   547  			err = fmt.Errorf("image %q wasn't found locally and it couldn't be pulled: %s", image, err)
   548  		}
   549  	}
   550  	return
   551  }
   552  
   553  func dockerCmd(c *check.C, args ...string) (string, int) {
   554  	out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
   555  	if err != nil {
   556  		c.Fatalf("%q failed with errors: %s, %v", strings.Join(args, " "), out, err)
   557  	}
   558  	return out, status
   559  }
   560  
   561  // execute a docker command with a timeout
   562  func dockerCmdWithTimeout(timeout time.Duration, args ...string) (string, int, error) {
   563  	out, status, err := runCommandWithOutputAndTimeout(exec.Command(dockerBinary, args...), timeout)
   564  	if err != nil {
   565  		return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
   566  	}
   567  	return out, status, err
   568  }
   569  
   570  // execute a docker command in a directory
   571  func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
   572  	dockerCommand := exec.Command(dockerBinary, args...)
   573  	dockerCommand.Dir = path
   574  	out, status, err := runCommandWithOutput(dockerCommand)
   575  	if err != nil {
   576  		return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
   577  	}
   578  	return out, status, err
   579  }
   580  
   581  // execute a docker command in a directory with a timeout
   582  func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...string) (string, int, error) {
   583  	dockerCommand := exec.Command(dockerBinary, args...)
   584  	dockerCommand.Dir = path
   585  	out, status, err := runCommandWithOutputAndTimeout(dockerCommand, timeout)
   586  	if err != nil {
   587  		return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
   588  	}
   589  	return out, status, err
   590  }
   591  
   592  func findContainerIP(c *check.C, id string, vargs ...string) string {
   593  	args := append(vargs, "inspect", "--format='{{ .NetworkSettings.IPAddress }}'", id)
   594  	cmd := exec.Command(dockerBinary, args...)
   595  	out, _, err := runCommandWithOutput(cmd)
   596  	if err != nil {
   597  		c.Fatal(err, out)
   598  	}
   599  
   600  	return strings.Trim(out, " \r\n'")
   601  }
   602  
   603  func (d *Daemon) findContainerIP(id string) string {
   604  	return findContainerIP(d.c, id, "--host", d.sock())
   605  }
   606  
   607  func getContainerCount() (int, error) {
   608  	const containers = "Containers:"
   609  
   610  	cmd := exec.Command(dockerBinary, "info")
   611  	out, _, err := runCommandWithOutput(cmd)
   612  	if err != nil {
   613  		return 0, err
   614  	}
   615  
   616  	lines := strings.Split(out, "\n")
   617  	for _, line := range lines {
   618  		if strings.Contains(line, containers) {
   619  			output := strings.TrimSpace(line)
   620  			output = strings.TrimLeft(output, containers)
   621  			output = strings.Trim(output, " ")
   622  			containerCount, err := strconv.Atoi(output)
   623  			if err != nil {
   624  				return 0, err
   625  			}
   626  			return containerCount, nil
   627  		}
   628  	}
   629  	return 0, fmt.Errorf("couldn't find the Container count in the output")
   630  }
   631  
   632  type FakeContext struct {
   633  	Dir string
   634  }
   635  
   636  func (f *FakeContext) Add(file, content string) error {
   637  	filepath := path.Join(f.Dir, file)
   638  	dirpath := path.Dir(filepath)
   639  	if dirpath != "." {
   640  		if err := os.MkdirAll(dirpath, 0755); err != nil {
   641  			return err
   642  		}
   643  	}
   644  	return ioutil.WriteFile(filepath, []byte(content), 0644)
   645  }
   646  
   647  func (f *FakeContext) Delete(file string) error {
   648  	filepath := path.Join(f.Dir, file)
   649  	return os.RemoveAll(filepath)
   650  }
   651  
   652  func (f *FakeContext) Close() error {
   653  	return os.RemoveAll(f.Dir)
   654  }
   655  
   656  func fakeContextFromDir(dir string) *FakeContext {
   657  	return &FakeContext{dir}
   658  }
   659  
   660  func fakeContextWithFiles(files map[string]string) (*FakeContext, error) {
   661  	tmp, err := ioutil.TempDir("", "fake-context")
   662  	if err != nil {
   663  		return nil, err
   664  	}
   665  	if err := os.Chmod(tmp, 0755); err != nil {
   666  		return nil, err
   667  	}
   668  
   669  	ctx := fakeContextFromDir(tmp)
   670  	for file, content := range files {
   671  		if err := ctx.Add(file, content); err != nil {
   672  			ctx.Close()
   673  			return nil, err
   674  		}
   675  	}
   676  	return ctx, nil
   677  }
   678  
   679  func fakeContextAddDockerfile(ctx *FakeContext, dockerfile string) error {
   680  	if err := ctx.Add("Dockerfile", dockerfile); err != nil {
   681  		ctx.Close()
   682  		return err
   683  	}
   684  	return nil
   685  }
   686  
   687  func fakeContext(dockerfile string, files map[string]string) (*FakeContext, error) {
   688  	ctx, err := fakeContextWithFiles(files)
   689  	if err != nil {
   690  		return nil, err
   691  	}
   692  	if err := fakeContextAddDockerfile(ctx, dockerfile); err != nil {
   693  		return nil, err
   694  	}
   695  	return ctx, nil
   696  }
   697  
   698  // FakeStorage is a static file server. It might be running locally or remotely
   699  // on test host.
   700  type FakeStorage interface {
   701  	Close() error
   702  	URL() string
   703  	CtxDir() string
   704  }
   705  
   706  // fakeStorage returns either a local or remote (at daemon machine) file server
   707  func fakeStorage(files map[string]string) (FakeStorage, error) {
   708  	ctx, err := fakeContextWithFiles(files)
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  	return fakeStorageWithContext(ctx)
   713  }
   714  
   715  // fakeStorageWithContext returns either a local or remote (at daemon machine) file server
   716  func fakeStorageWithContext(ctx *FakeContext) (FakeStorage, error) {
   717  	if isLocalDaemon {
   718  		return newLocalFakeStorage(ctx)
   719  	}
   720  	return newRemoteFileServer(ctx)
   721  }
   722  
   723  // localFileStorage is a file storage on the running machine
   724  type localFileStorage struct {
   725  	*FakeContext
   726  	*httptest.Server
   727  }
   728  
   729  func (s *localFileStorage) URL() string {
   730  	return s.Server.URL
   731  }
   732  
   733  func (s *localFileStorage) CtxDir() string {
   734  	return s.FakeContext.Dir
   735  }
   736  
   737  func (s *localFileStorage) Close() error {
   738  	defer s.Server.Close()
   739  	return s.FakeContext.Close()
   740  }
   741  
   742  func newLocalFakeStorage(ctx *FakeContext) (*localFileStorage, error) {
   743  	handler := http.FileServer(http.Dir(ctx.Dir))
   744  	server := httptest.NewServer(handler)
   745  	return &localFileStorage{
   746  		FakeContext: ctx,
   747  		Server:      server,
   748  	}, nil
   749  }
   750  
   751  // remoteFileServer is a containerized static file server started on the remote
   752  // testing machine to be used in URL-accepting docker build functionality.
   753  type remoteFileServer struct {
   754  	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
   755  	container string
   756  	image     string
   757  	ctx       *FakeContext
   758  }
   759  
   760  func (f *remoteFileServer) URL() string {
   761  	u := url.URL{
   762  		Scheme: "http",
   763  		Host:   f.host}
   764  	return u.String()
   765  }
   766  
   767  func (f *remoteFileServer) CtxDir() string {
   768  	return f.ctx.Dir
   769  }
   770  
   771  func (f *remoteFileServer) Close() error {
   772  	defer func() {
   773  		if f.ctx != nil {
   774  			f.ctx.Close()
   775  		}
   776  		if f.image != "" {
   777  			deleteImages(f.image)
   778  		}
   779  	}()
   780  	if f.container == "" {
   781  		return nil
   782  	}
   783  	return deleteContainer(f.container)
   784  }
   785  
   786  func newRemoteFileServer(ctx *FakeContext) (*remoteFileServer, error) {
   787  	var (
   788  		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
   789  		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
   790  	)
   791  
   792  	// Build the image
   793  	if err := fakeContextAddDockerfile(ctx, `FROM httpserver
   794  COPY . /static`); err != nil {
   795  		return nil, fmt.Errorf("Cannot add Dockerfile to context: %v", err)
   796  	}
   797  	if _, err := buildImageFromContext(image, ctx, false); err != nil {
   798  		return nil, fmt.Errorf("failed building file storage container image: %v", err)
   799  	}
   800  
   801  	// Start the container
   802  	runCmd := exec.Command(dockerBinary, "run", "-d", "-P", "--name", container, image)
   803  	if out, ec, err := runCommandWithOutput(runCmd); err != nil {
   804  		return nil, fmt.Errorf("failed to start file storage container. ec=%v\nout=%s\nerr=%v", ec, out, err)
   805  	}
   806  
   807  	// Find out the system assigned port
   808  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "port", container, "80/tcp"))
   809  	if err != nil {
   810  		return nil, fmt.Errorf("failed to find container port: err=%v\nout=%s", err, out)
   811  	}
   812  
   813  	return &remoteFileServer{
   814  		container: container,
   815  		image:     image,
   816  		host:      strings.Trim(out, "\n"),
   817  		ctx:       ctx}, nil
   818  }
   819  
   820  func inspectFieldAndMarshall(name, field string, output interface{}) error {
   821  	str, err := inspectFieldJSON(name, field)
   822  	if err != nil {
   823  		return err
   824  	}
   825  
   826  	return json.Unmarshal([]byte(str), output)
   827  }
   828  
   829  func inspectFilter(name, filter string) (string, error) {
   830  	format := fmt.Sprintf("{{%s}}", filter)
   831  	inspectCmd := exec.Command(dockerBinary, "inspect", "-f", format, name)
   832  	out, exitCode, err := runCommandWithOutput(inspectCmd)
   833  	if err != nil || exitCode != 0 {
   834  		return "", fmt.Errorf("failed to inspect container %s: %s", name, out)
   835  	}
   836  	return strings.TrimSpace(out), nil
   837  }
   838  
   839  func inspectField(name, field string) (string, error) {
   840  	return inspectFilter(name, fmt.Sprintf(".%s", field))
   841  }
   842  
   843  func inspectFieldJSON(name, field string) (string, error) {
   844  	return inspectFilter(name, fmt.Sprintf("json .%s", field))
   845  }
   846  
   847  func inspectFieldMap(name, path, field string) (string, error) {
   848  	return inspectFilter(name, fmt.Sprintf("index .%s %q", path, field))
   849  }
   850  
   851  func getIDByName(name string) (string, error) {
   852  	return inspectField(name, "Id")
   853  }
   854  
   855  // getContainerState returns the exit code of the container
   856  // and true if it's running
   857  // the exit code should be ignored if it's running
   858  func getContainerState(c *check.C, id string) (int, bool, error) {
   859  	var (
   860  		exitStatus int
   861  		running    bool
   862  	)
   863  	out, exitCode := dockerCmd(c, "inspect", "--format={{.State.Running}} {{.State.ExitCode}}", id)
   864  	if exitCode != 0 {
   865  		return 0, false, fmt.Errorf("%q doesn't exist: %s", id, out)
   866  	}
   867  
   868  	out = strings.Trim(out, "\n")
   869  	splitOutput := strings.Split(out, " ")
   870  	if len(splitOutput) != 2 {
   871  		return 0, false, fmt.Errorf("failed to get container state: output is broken")
   872  	}
   873  	if splitOutput[0] == "true" {
   874  		running = true
   875  	}
   876  	if n, err := strconv.Atoi(splitOutput[1]); err == nil {
   877  		exitStatus = n
   878  	} else {
   879  		return 0, false, fmt.Errorf("failed to get container state: couldn't parse integer")
   880  	}
   881  
   882  	return exitStatus, running, nil
   883  }
   884  
   885  func buildImageWithOut(name, dockerfile string, useCache bool) (string, string, error) {
   886  	args := []string{"build", "-t", name}
   887  	if !useCache {
   888  		args = append(args, "--no-cache")
   889  	}
   890  	args = append(args, "-")
   891  	buildCmd := exec.Command(dockerBinary, args...)
   892  	buildCmd.Stdin = strings.NewReader(dockerfile)
   893  	out, exitCode, err := runCommandWithOutput(buildCmd)
   894  	if err != nil || exitCode != 0 {
   895  		return "", out, fmt.Errorf("failed to build the image: %s", out)
   896  	}
   897  	id, err := getIDByName(name)
   898  	if err != nil {
   899  		return "", out, err
   900  	}
   901  	return id, out, nil
   902  }
   903  
   904  func buildImageWithStdoutStderr(name, dockerfile string, useCache bool) (string, string, string, error) {
   905  	args := []string{"build", "-t", name}
   906  	if !useCache {
   907  		args = append(args, "--no-cache")
   908  	}
   909  	args = append(args, "-")
   910  	buildCmd := exec.Command(dockerBinary, args...)
   911  	buildCmd.Stdin = strings.NewReader(dockerfile)
   912  	stdout, stderr, exitCode, err := runCommandWithStdoutStderr(buildCmd)
   913  	if err != nil || exitCode != 0 {
   914  		return "", stdout, stderr, fmt.Errorf("failed to build the image: %s", stdout)
   915  	}
   916  	id, err := getIDByName(name)
   917  	if err != nil {
   918  		return "", stdout, stderr, err
   919  	}
   920  	return id, stdout, stderr, nil
   921  }
   922  
   923  func buildImage(name, dockerfile string, useCache bool) (string, error) {
   924  	id, _, err := buildImageWithOut(name, dockerfile, useCache)
   925  	return id, err
   926  }
   927  
   928  func buildImageFromContext(name string, ctx *FakeContext, useCache bool) (string, error) {
   929  	args := []string{"build", "-t", name}
   930  	if !useCache {
   931  		args = append(args, "--no-cache")
   932  	}
   933  	args = append(args, ".")
   934  	buildCmd := exec.Command(dockerBinary, args...)
   935  	buildCmd.Dir = ctx.Dir
   936  	out, exitCode, err := runCommandWithOutput(buildCmd)
   937  	if err != nil || exitCode != 0 {
   938  		return "", fmt.Errorf("failed to build the image: %s", out)
   939  	}
   940  	return getIDByName(name)
   941  }
   942  
   943  func buildImageFromPath(name, path string, useCache bool) (string, error) {
   944  	args := []string{"build", "-t", name}
   945  	if !useCache {
   946  		args = append(args, "--no-cache")
   947  	}
   948  	args = append(args, path)
   949  	buildCmd := exec.Command(dockerBinary, args...)
   950  	out, exitCode, err := runCommandWithOutput(buildCmd)
   951  	if err != nil || exitCode != 0 {
   952  		return "", fmt.Errorf("failed to build the image: %s", out)
   953  	}
   954  	return getIDByName(name)
   955  }
   956  
   957  type GitServer interface {
   958  	URL() string
   959  	Close() error
   960  }
   961  
   962  type localGitServer struct {
   963  	*httptest.Server
   964  }
   965  
   966  func (r *localGitServer) Close() error {
   967  	r.Server.Close()
   968  	return nil
   969  }
   970  
   971  func (r *localGitServer) URL() string {
   972  	return r.Server.URL
   973  }
   974  
   975  type FakeGIT struct {
   976  	root    string
   977  	server  GitServer
   978  	RepoURL string
   979  }
   980  
   981  func (g *FakeGIT) Close() {
   982  	g.server.Close()
   983  	os.RemoveAll(g.root)
   984  }
   985  
   986  func fakeGIT(name string, files map[string]string, enforceLocalServer bool) (*FakeGIT, error) {
   987  	ctx, err := fakeContextWithFiles(files)
   988  	if err != nil {
   989  		return nil, err
   990  	}
   991  	defer ctx.Close()
   992  	curdir, err := os.Getwd()
   993  	if err != nil {
   994  		return nil, err
   995  	}
   996  	defer os.Chdir(curdir)
   997  
   998  	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
   999  		return nil, fmt.Errorf("error trying to init repo: %s (%s)", err, output)
  1000  	}
  1001  	err = os.Chdir(ctx.Dir)
  1002  	if err != nil {
  1003  		return nil, err
  1004  	}
  1005  	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
  1006  		return nil, fmt.Errorf("error trying to set 'user.name': %s (%s)", err, output)
  1007  	}
  1008  	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
  1009  		return nil, fmt.Errorf("error trying to set 'user.email': %s (%s)", err, output)
  1010  	}
  1011  	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
  1012  		return nil, fmt.Errorf("error trying to add files to repo: %s (%s)", err, output)
  1013  	}
  1014  	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
  1015  		return nil, fmt.Errorf("error trying to commit to repo: %s (%s)", err, output)
  1016  	}
  1017  
  1018  	root, err := ioutil.TempDir("", "docker-test-git-repo")
  1019  	if err != nil {
  1020  		return nil, err
  1021  	}
  1022  	repoPath := filepath.Join(root, name+".git")
  1023  	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
  1024  		os.RemoveAll(root)
  1025  		return nil, fmt.Errorf("error trying to clone --bare: %s (%s)", err, output)
  1026  	}
  1027  	err = os.Chdir(repoPath)
  1028  	if err != nil {
  1029  		os.RemoveAll(root)
  1030  		return nil, err
  1031  	}
  1032  	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
  1033  		os.RemoveAll(root)
  1034  		return nil, fmt.Errorf("error trying to git update-server-info: %s (%s)", err, output)
  1035  	}
  1036  	err = os.Chdir(curdir)
  1037  	if err != nil {
  1038  		os.RemoveAll(root)
  1039  		return nil, err
  1040  	}
  1041  
  1042  	var server GitServer
  1043  	if !enforceLocalServer {
  1044  		// use fakeStorage server, which might be local or remote (at test daemon)
  1045  		server, err = fakeStorageWithContext(fakeContextFromDir(root))
  1046  		if err != nil {
  1047  			return nil, fmt.Errorf("cannot start fake storage: %v", err)
  1048  		}
  1049  	} else {
  1050  		// always start a local http server on CLI test machin
  1051  		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
  1052  		server = &localGitServer{httpServer}
  1053  	}
  1054  	return &FakeGIT{
  1055  		root:    root,
  1056  		server:  server,
  1057  		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
  1058  	}, nil
  1059  }
  1060  
  1061  // Write `content` to the file at path `dst`, creating it if necessary,
  1062  // as well as any missing directories.
  1063  // The file is truncated if it already exists.
  1064  // Call c.Fatal() at the first error.
  1065  func writeFile(dst, content string, c *check.C) {
  1066  	// Create subdirectories if necessary
  1067  	if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
  1068  		c.Fatal(err)
  1069  	}
  1070  	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
  1071  	if err != nil {
  1072  		c.Fatal(err)
  1073  	}
  1074  	// Write content (truncate if it exists)
  1075  	if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
  1076  		c.Fatal(err)
  1077  	}
  1078  }
  1079  
  1080  // Return the contents of file at path `src`.
  1081  // Call c.Fatal() at the first error (including if the file doesn't exist)
  1082  func readFile(src string, c *check.C) (content string) {
  1083  	data, err := ioutil.ReadFile(src)
  1084  	if err != nil {
  1085  		c.Fatal(err)
  1086  	}
  1087  
  1088  	return string(data)
  1089  }
  1090  
  1091  func containerStorageFile(containerId, basename string) string {
  1092  	return filepath.Join("/var/lib/docker/containers", containerId, basename)
  1093  }
  1094  
  1095  // docker commands that use this function must be run with the '-d' switch.
  1096  func runCommandAndReadContainerFile(filename string, cmd *exec.Cmd) ([]byte, error) {
  1097  	out, _, err := runCommandWithOutput(cmd)
  1098  	if err != nil {
  1099  		return nil, fmt.Errorf("%v: %q", err, out)
  1100  	}
  1101  
  1102  	time.Sleep(1 * time.Second)
  1103  
  1104  	contID := strings.TrimSpace(out)
  1105  
  1106  	return readContainerFile(contID, filename)
  1107  }
  1108  
  1109  func readContainerFile(containerId, filename string) ([]byte, error) {
  1110  	f, err := os.Open(containerStorageFile(containerId, filename))
  1111  	if err != nil {
  1112  		return nil, err
  1113  	}
  1114  	defer f.Close()
  1115  
  1116  	content, err := ioutil.ReadAll(f)
  1117  	if err != nil {
  1118  		return nil, err
  1119  	}
  1120  
  1121  	return content, nil
  1122  }
  1123  
  1124  func readContainerFileWithExec(containerId, filename string) ([]byte, error) {
  1125  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "exec", containerId, "cat", filename))
  1126  	return []byte(out), err
  1127  }
  1128  
  1129  // daemonTime provides the current time on the daemon host
  1130  func daemonTime(c *check.C) time.Time {
  1131  	if isLocalDaemon {
  1132  		return time.Now()
  1133  	}
  1134  
  1135  	status, body, err := sockRequest("GET", "/info", nil)
  1136  	c.Assert(status, check.Equals, http.StatusOK)
  1137  	c.Assert(err, check.IsNil)
  1138  
  1139  	type infoJSON struct {
  1140  		SystemTime string
  1141  	}
  1142  	var info infoJSON
  1143  	if err = json.Unmarshal(body, &info); err != nil {
  1144  		c.Fatalf("unable to unmarshal /info response: %v", err)
  1145  	}
  1146  
  1147  	dt, err := time.Parse(time.RFC3339Nano, info.SystemTime)
  1148  	if err != nil {
  1149  		c.Fatal(err)
  1150  	}
  1151  	return dt
  1152  }
  1153  
  1154  func setupRegistry(c *check.C) *testRegistryV2 {
  1155  	testRequires(c, RegistryHosting)
  1156  	reg, err := newTestRegistryV2(c)
  1157  	if err != nil {
  1158  		c.Fatal(err)
  1159  	}
  1160  
  1161  	// Wait for registry to be ready to serve requests.
  1162  	for i := 0; i != 5; i++ {
  1163  		if err = reg.Ping(); err == nil {
  1164  			break
  1165  		}
  1166  		time.Sleep(100 * time.Millisecond)
  1167  	}
  1168  
  1169  	if err != nil {
  1170  		c.Fatal("Timeout waiting for test registry to become available")
  1171  	}
  1172  	return reg
  1173  }
  1174  
  1175  // appendBaseEnv appends the minimum set of environment variables to exec the
  1176  // docker cli binary for testing with correct configuration to the given env
  1177  // list.
  1178  func appendBaseEnv(env []string) []string {
  1179  	preserveList := []string{
  1180  		// preserve remote test host
  1181  		"DOCKER_HOST",
  1182  
  1183  		// windows: requires preserving SystemRoot, otherwise dial tcp fails
  1184  		// with "GetAddrInfoW: A non-recoverable error occurred during a database lookup."
  1185  		"SystemRoot",
  1186  	}
  1187  
  1188  	for _, key := range preserveList {
  1189  		if val := os.Getenv(key); val != "" {
  1190  			env = append(env, fmt.Sprintf("%s=%s", key, val))
  1191  		}
  1192  	}
  1193  	return env
  1194  }