mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Merge branch 'master' into creack-merge-master
Conflicts: api_params.go graph.go graph_test.go image.go integration/api_test.go integration/container_test.go integration/runtime_test.go runtime.go
This commit is contained in:
		
						commit
						28d4cbbc59
					
				
					 62 changed files with 2852 additions and 2209 deletions
				
			
		
							
								
								
									
										2
									
								
								AUTHORS
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								AUTHORS
									
										
									
									
									
								
							| 
						 | 
					@ -44,6 +44,7 @@ Daniel Nordberg <dnordberg@gmail.com>
 | 
				
			||||||
Daniel Robinson <gottagetmac@gmail.com>
 | 
					Daniel Robinson <gottagetmac@gmail.com>
 | 
				
			||||||
Daniel Von Fange <daniel@leancoder.com>
 | 
					Daniel Von Fange <daniel@leancoder.com>
 | 
				
			||||||
Daniel YC Lin <dlin.tw@gmail.com>
 | 
					Daniel YC Lin <dlin.tw@gmail.com>
 | 
				
			||||||
 | 
					Darren Coxall <darren@darrencoxall.com>
 | 
				
			||||||
David Calavera <david.calavera@gmail.com>
 | 
					David Calavera <david.calavera@gmail.com>
 | 
				
			||||||
David Sissitka <me@dsissitka.com>
 | 
					David Sissitka <me@dsissitka.com>
 | 
				
			||||||
Deni Bertovic <deni@kset.org>
 | 
					Deni Bertovic <deni@kset.org>
 | 
				
			||||||
| 
						 | 
					@ -120,6 +121,7 @@ Marko Mikulicic <mmikulicic@gmail.com>
 | 
				
			||||||
Markus Fix <lispmeister@gmail.com>
 | 
					Markus Fix <lispmeister@gmail.com>
 | 
				
			||||||
Martin Redmond <martin@tinychat.com>
 | 
					Martin Redmond <martin@tinychat.com>
 | 
				
			||||||
Matt Apperson <me@mattapperson.com>
 | 
					Matt Apperson <me@mattapperson.com>
 | 
				
			||||||
 | 
					Mathieu Le Marec - Pasquet <kiorky@cryptelium.net>
 | 
				
			||||||
Matt Bachmann <bachmann.matt@gmail.com>
 | 
					Matt Bachmann <bachmann.matt@gmail.com>
 | 
				
			||||||
Matthew Mueller <mattmuelle@gmail.com>
 | 
					Matthew Mueller <mattmuelle@gmail.com>
 | 
				
			||||||
Maxim Treskin <zerthurd@gmail.com>
 | 
					Maxim Treskin <zerthurd@gmail.com>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ run	apt-get install -y -q mercurial
 | 
				
			||||||
run	apt-get install -y -q build-essential libsqlite3-dev
 | 
					run	apt-get install -y -q build-essential libsqlite3-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install Go
 | 
					# Install Go
 | 
				
			||||||
run	curl -s https://go.googlecode.com/files/go1.2rc4.src.tar.gz | tar -v -C /usr/local -xz
 | 
					run	curl -s https://go.googlecode.com/files/go1.2rc5.src.tar.gz | tar -v -C /usr/local -xz
 | 
				
			||||||
env	PATH	/usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
 | 
					env	PATH	/usr/local/go/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
 | 
				
			||||||
env	GOPATH	/go:/go/src/github.com/dotcloud/docker/vendor
 | 
					env	GOPATH	/go:/go/src/github.com/dotcloud/docker/vendor
 | 
				
			||||||
run	cd /usr/local/go/src && ./make.bash && go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
 | 
					run	cd /usr/local/go/src && ./make.bash && go install -ldflags '-w -linkmode external -extldflags "-static -Wl,--unresolved-symbols=ignore-in-shared-libs"' -tags netgo -a std
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								Vagrantfile
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								Vagrantfile
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -70,7 +70,7 @@ SCRIPT
 | 
				
			||||||
# trigger dkms to build the virtualbox guest module install.
 | 
					# trigger dkms to build the virtualbox guest module install.
 | 
				
			||||||
$vbox_script = <<VBOX_SCRIPT + $script
 | 
					$vbox_script = <<VBOX_SCRIPT + $script
 | 
				
			||||||
# Install the VirtualBox guest additions if they aren't already installed.
 | 
					# Install the VirtualBox guest additions if they aren't already installed.
 | 
				
			||||||
if [ ! -d /opt/VBoxGuestAdditions-4.2.12/ ]; then
 | 
					if [ ! -d /opt/VBoxGuestAdditions-4.3.2/ ]; then
 | 
				
			||||||
    # Update remote package metadata.  'apt-get update' is idempotent.
 | 
					    # Update remote package metadata.  'apt-get update' is idempotent.
 | 
				
			||||||
    apt-get update -q
 | 
					    apt-get update -q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,9 +79,9 @@ if [ ! -d /opt/VBoxGuestAdditions-4.2.12/ ]; then
 | 
				
			||||||
    apt-get install -q -y linux-headers-generic-lts-raring dkms
 | 
					    apt-get install -q -y linux-headers-generic-lts-raring dkms
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    echo 'Downloading VBox Guest Additions...'
 | 
					    echo 'Downloading VBox Guest Additions...'
 | 
				
			||||||
    wget -cq http://dlc.sun.com.edgesuite.net/virtualbox/4.2.12/VBoxGuestAdditions_4.2.12.iso
 | 
					    wget -cq http://dlc.sun.com.edgesuite.net/virtualbox/4.3.2/VBoxGuestAdditions_4.3.2.iso
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.2.12.iso /mnt
 | 
					    mount -o loop,ro /home/vagrant/VBoxGuestAdditions_4.3.2.iso /mnt
 | 
				
			||||||
    /mnt/VBoxLinuxAdditions.run --nox11
 | 
					    /mnt/VBoxLinuxAdditions.run --nox11
 | 
				
			||||||
    umount /mnt
 | 
					    umount /mnt
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										44
									
								
								api.go
									
										
									
									
									
								
							
							
						
						
									
										44
									
								
								api.go
									
										
									
									
									
								
							| 
						 | 
					@ -149,13 +149,12 @@ func postContainersKill(srv *Server, version float64, w http.ResponseWriter, r *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signal := 0
 | 
						signal := 0
 | 
				
			||||||
	if r != nil {
 | 
						if r != nil {
 | 
				
			||||||
		s := r.Form.Get("signal")
 | 
							if s := r.Form.Get("signal"); s != "" {
 | 
				
			||||||
		if s != "" {
 | 
								s, err := strconv.Atoi(s)
 | 
				
			||||||
			if s, err := strconv.Atoi(s); err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				signal = s
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								signal = s
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := srv.ContainerKill(name, signal); err != nil {
 | 
						if err := srv.ContainerKill(name, signal); err != nil {
 | 
				
			||||||
| 
						 | 
					@ -201,9 +200,8 @@ func getImagesJSON(srv *Server, version float64, w http.ResponseWriter, r *http.
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return writeJSON(w, http.StatusOK, outs2)
 | 
							return writeJSON(w, http.StatusOK, outs2)
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return writeJSON(w, http.StatusOK, outs)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return writeJSON(w, http.StatusOK, outs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 | 
					func getImagesViz(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 | 
				
			||||||
| 
						 | 
					@ -316,13 +314,10 @@ func getContainersTop(srv *Server, version float64, w http.ResponseWriter, r *ht
 | 
				
			||||||
	if err := parseForm(r); err != nil {
 | 
						if err := parseForm(r); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	name := vars["name"]
 | 
						procsStr, err := srv.ContainerTop(vars["name"], r.Form.Get("ps_args"))
 | 
				
			||||||
	ps_args := r.Form.Get("ps_args")
 | 
					 | 
				
			||||||
	procsStr, err := srv.ContainerTop(name, ps_args)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return writeJSON(w, http.StatusOK, procsStr)
 | 
						return writeJSON(w, http.StatusOK, procsStr)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,13 +345,12 @@ func getContainersJSON(srv *Server, version float64, w http.ResponseWriter, r *h
 | 
				
			||||||
	if version < 1.5 {
 | 
						if version < 1.5 {
 | 
				
			||||||
		outs2 := []APIContainersOld{}
 | 
							outs2 := []APIContainersOld{}
 | 
				
			||||||
		for _, ctnr := range outs {
 | 
							for _, ctnr := range outs {
 | 
				
			||||||
			outs2 = append(outs2, ctnr.ToLegacy())
 | 
								outs2 = append(outs2, *ctnr.ToLegacy())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return writeJSON(w, http.StatusOK, outs2)
 | 
							return writeJSON(w, http.StatusOK, outs2)
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return writeJSON(w, http.StatusOK, outs)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return writeJSON(w, http.StatusOK, outs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 | 
					func postImagesTag(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 | 
				
			||||||
| 
						 | 
					@ -640,12 +634,10 @@ func deleteImages(srv *Server, version float64, w http.ResponseWriter, r *http.R
 | 
				
			||||||
	if imgs != nil {
 | 
						if imgs != nil {
 | 
				
			||||||
		if len(imgs) != 0 {
 | 
							if len(imgs) != 0 {
 | 
				
			||||||
			return writeJSON(w, http.StatusOK, imgs)
 | 
								return writeJSON(w, http.StatusOK, imgs)
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return fmt.Errorf("Conflict, %s wasn't deleted", name)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
							return fmt.Errorf("Conflict, %s wasn't deleted", name)
 | 
				
			||||||
		w.WriteHeader(http.StatusNoContent)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						w.WriteHeader(http.StatusNoContent)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -930,7 +922,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		c, err := mkBuildContext(string(dockerFile), nil)
 | 
							c, err := MkBuildContext(string(dockerFile), nil)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1108,6 +1100,20 @@ func createRouter(srv *Server, logging bool) (*mux.Router, error) {
 | 
				
			||||||
	return r, nil
 | 
						return r, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ServeRequest processes a single http request to the docker remote api.
 | 
				
			||||||
 | 
					// FIXME: refactor this to be part of Server and not require re-creating a new
 | 
				
			||||||
 | 
					// router each time. This requires first moving ListenAndServe into Server.
 | 
				
			||||||
 | 
					func ServeRequest(srv *Server, apiversion float64, w http.ResponseWriter, req *http.Request) error {
 | 
				
			||||||
 | 
						router, err := createRouter(srv, false)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Insert APIVERSION into the request as a convenience
 | 
				
			||||||
 | 
						req.URL.Path = fmt.Sprintf("/v%g%s", apiversion, req.URL.Path)
 | 
				
			||||||
 | 
						router.ServeHTTP(w, req)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
 | 
					func ListenAndServe(proto, addr string, srv *Server, logging bool) error {
 | 
				
			||||||
	log.Printf("Listening for HTTP on %s (%s)\n", addr, proto)
 | 
						log.Printf("Listening for HTTP on %s (%s)\n", addr, proto)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										280
									
								
								api_params.go
									
										
									
									
									
								
							
							
						
						
									
										280
									
								
								api_params.go
									
										
									
									
									
								
							| 
						 | 
					@ -2,151 +2,149 @@ package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "strings"
 | 
					import "strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type APIHistory struct {
 | 
					type (
 | 
				
			||||||
	ID        string   `json:"Id"`
 | 
						APIHistory struct {
 | 
				
			||||||
	Tags      []string `json:",omitempty"`
 | 
							ID        string   `json:"Id"`
 | 
				
			||||||
	Created   int64
 | 
							Tags      []string `json:",omitempty"`
 | 
				
			||||||
	CreatedBy string `json:",omitempty"`
 | 
							Created   int64
 | 
				
			||||||
	Size      int64
 | 
							CreatedBy string `json:",omitempty"`
 | 
				
			||||||
}
 | 
							Size      int64
 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIImages struct {
 | 
					 | 
				
			||||||
	ID          string   `json:"Id"`
 | 
					 | 
				
			||||||
	RepoTags    []string `json:",omitempty"`
 | 
					 | 
				
			||||||
	Created     int64
 | 
					 | 
				
			||||||
	Size        int64
 | 
					 | 
				
			||||||
	VirtualSize int64
 | 
					 | 
				
			||||||
	ParentId    string `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIImagesOld struct {
 | 
					 | 
				
			||||||
	Repository  string `json:",omitempty"`
 | 
					 | 
				
			||||||
	Tag         string `json:",omitempty"`
 | 
					 | 
				
			||||||
	ID          string `json:"Id"`
 | 
					 | 
				
			||||||
	Created     int64
 | 
					 | 
				
			||||||
	Size        int64
 | 
					 | 
				
			||||||
	VirtualSize int64
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *APIImages) ToLegacy() []APIImagesOld {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	outs := []APIImagesOld{}
 | 
					 | 
				
			||||||
	for _, repotag := range self.RepoTags {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		components := strings.SplitN(repotag, ":", 2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		outs = append(outs, APIImagesOld{
 | 
					 | 
				
			||||||
			ID:          self.ID,
 | 
					 | 
				
			||||||
			Repository:  components[0],
 | 
					 | 
				
			||||||
			Tag:         components[1],
 | 
					 | 
				
			||||||
			Created:     self.Created,
 | 
					 | 
				
			||||||
			Size:        self.Size,
 | 
					 | 
				
			||||||
			VirtualSize: self.VirtualSize,
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIImages struct {
 | 
				
			||||||
 | 
							ID          string   `json:"Id"`
 | 
				
			||||||
 | 
							RepoTags    []string `json:",omitempty"`
 | 
				
			||||||
 | 
							Created     int64
 | 
				
			||||||
 | 
							Size        int64
 | 
				
			||||||
 | 
							VirtualSize int64
 | 
				
			||||||
 | 
							ParentId    string `json:",omitempty"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIImagesOld struct {
 | 
				
			||||||
 | 
							Repository  string `json:",omitempty"`
 | 
				
			||||||
 | 
							Tag         string `json:",omitempty"`
 | 
				
			||||||
 | 
							ID          string `json:"Id"`
 | 
				
			||||||
 | 
							Created     int64
 | 
				
			||||||
 | 
							Size        int64
 | 
				
			||||||
 | 
							VirtualSize int64
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIInfo struct {
 | 
				
			||||||
 | 
							Debug              bool
 | 
				
			||||||
 | 
							Containers         int
 | 
				
			||||||
 | 
							Images             int
 | 
				
			||||||
 | 
							Driver             string      `json:",omitempty"`
 | 
				
			||||||
 | 
							DriverStatus       [][2]string `json:",omitempty"`
 | 
				
			||||||
 | 
							NFd                int         `json:",omitempty"`
 | 
				
			||||||
 | 
							NGoroutines        int         `json:",omitempty"`
 | 
				
			||||||
 | 
							MemoryLimit        bool        `json:",omitempty"`
 | 
				
			||||||
 | 
							SwapLimit          bool        `json:",omitempty"`
 | 
				
			||||||
 | 
							IPv4Forwarding     bool        `json:",omitempty"`
 | 
				
			||||||
 | 
							LXCVersion         string      `json:",omitempty"`
 | 
				
			||||||
 | 
							NEventsListener    int         `json:",omitempty"`
 | 
				
			||||||
 | 
							KernelVersion      string      `json:",omitempty"`
 | 
				
			||||||
 | 
							IndexServerAddress string      `json:",omitempty"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APITop struct {
 | 
				
			||||||
 | 
							Titles    []string
 | 
				
			||||||
 | 
							Processes [][]string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIRmi struct {
 | 
				
			||||||
 | 
							Deleted  string `json:",omitempty"`
 | 
				
			||||||
 | 
							Untagged string `json:",omitempty"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIContainers struct {
 | 
				
			||||||
 | 
							ID         string `json:"Id"`
 | 
				
			||||||
 | 
							Image      string
 | 
				
			||||||
 | 
							Command    string
 | 
				
			||||||
 | 
							Created    int64
 | 
				
			||||||
 | 
							Status     string
 | 
				
			||||||
 | 
							Ports      []APIPort
 | 
				
			||||||
 | 
							SizeRw     int64
 | 
				
			||||||
 | 
							SizeRootFs int64
 | 
				
			||||||
 | 
							Names      []string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIContainersOld struct {
 | 
				
			||||||
 | 
							ID         string `json:"Id"`
 | 
				
			||||||
 | 
							Image      string
 | 
				
			||||||
 | 
							Command    string
 | 
				
			||||||
 | 
							Created    int64
 | 
				
			||||||
 | 
							Status     string
 | 
				
			||||||
 | 
							Ports      string
 | 
				
			||||||
 | 
							SizeRw     int64
 | 
				
			||||||
 | 
							SizeRootFs int64
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIID struct {
 | 
				
			||||||
 | 
							ID string `json:"Id"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIRun struct {
 | 
				
			||||||
 | 
							ID       string   `json:"Id"`
 | 
				
			||||||
 | 
							Warnings []string `json:",omitempty"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIPort struct {
 | 
				
			||||||
 | 
							PrivatePort int64
 | 
				
			||||||
 | 
							PublicPort  int64
 | 
				
			||||||
 | 
							Type        string
 | 
				
			||||||
 | 
							IP          string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIVersion struct {
 | 
				
			||||||
 | 
							Version   string
 | 
				
			||||||
 | 
							GitCommit string `json:",omitempty"`
 | 
				
			||||||
 | 
							GoVersion string `json:",omitempty"`
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIWait struct {
 | 
				
			||||||
 | 
							StatusCode int
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIAuth struct {
 | 
				
			||||||
 | 
							Status string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APIImageConfig struct {
 | 
				
			||||||
 | 
							ID string `json:"Id"`
 | 
				
			||||||
 | 
							*Config
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						APICopy struct {
 | 
				
			||||||
 | 
							Resource string
 | 
				
			||||||
 | 
							HostPath string
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (api APIImages) ToLegacy() []APIImagesOld {
 | 
				
			||||||
 | 
						outs := []APIImagesOld{}
 | 
				
			||||||
 | 
						for _, repotag := range api.RepoTags {
 | 
				
			||||||
 | 
							components := strings.SplitN(repotag, ":", 2)
 | 
				
			||||||
 | 
							outs = append(outs, APIImagesOld{
 | 
				
			||||||
 | 
								ID:          api.ID,
 | 
				
			||||||
 | 
								Repository:  components[0],
 | 
				
			||||||
 | 
								Tag:         components[1],
 | 
				
			||||||
 | 
								Created:     api.Created,
 | 
				
			||||||
 | 
								Size:        api.Size,
 | 
				
			||||||
 | 
								VirtualSize: api.VirtualSize,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return outs
 | 
						return outs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type APIInfo struct {
 | 
					func (api APIContainers) ToLegacy() *APIContainersOld {
 | 
				
			||||||
	Debug              bool
 | 
						return &APIContainersOld{
 | 
				
			||||||
	Containers         int
 | 
							ID:         api.ID,
 | 
				
			||||||
	Images             int
 | 
							Image:      api.Image,
 | 
				
			||||||
	Driver             string      `json:",omitempty"`
 | 
							Command:    api.Command,
 | 
				
			||||||
	DriverStatus       [][2]string `json:",omitempty"`
 | 
							Created:    api.Created,
 | 
				
			||||||
	NFd                int         `json:",omitempty"`
 | 
							Status:     api.Status,
 | 
				
			||||||
	NGoroutines        int         `json:",omitempty"`
 | 
							Ports:      displayablePorts(api.Ports),
 | 
				
			||||||
	MemoryLimit        bool        `json:",omitempty"`
 | 
							SizeRw:     api.SizeRw,
 | 
				
			||||||
	SwapLimit          bool        `json:",omitempty"`
 | 
							SizeRootFs: api.SizeRootFs,
 | 
				
			||||||
	IPv4Forwarding     bool        `json:",omitempty"`
 | 
					 | 
				
			||||||
	LXCVersion         string      `json:",omitempty"`
 | 
					 | 
				
			||||||
	NEventsListener    int         `json:",omitempty"`
 | 
					 | 
				
			||||||
	KernelVersion      string      `json:",omitempty"`
 | 
					 | 
				
			||||||
	IndexServerAddress string      `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APITop struct {
 | 
					 | 
				
			||||||
	Titles    []string
 | 
					 | 
				
			||||||
	Processes [][]string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIRmi struct {
 | 
					 | 
				
			||||||
	Deleted  string `json:",omitempty"`
 | 
					 | 
				
			||||||
	Untagged string `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIContainers struct {
 | 
					 | 
				
			||||||
	ID         string `json:"Id"`
 | 
					 | 
				
			||||||
	Image      string
 | 
					 | 
				
			||||||
	Command    string
 | 
					 | 
				
			||||||
	Created    int64
 | 
					 | 
				
			||||||
	Status     string
 | 
					 | 
				
			||||||
	Ports      []APIPort
 | 
					 | 
				
			||||||
	SizeRw     int64
 | 
					 | 
				
			||||||
	SizeRootFs int64
 | 
					 | 
				
			||||||
	Names      []string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *APIContainers) ToLegacy() APIContainersOld {
 | 
					 | 
				
			||||||
	return APIContainersOld{
 | 
					 | 
				
			||||||
		ID:         self.ID,
 | 
					 | 
				
			||||||
		Image:      self.Image,
 | 
					 | 
				
			||||||
		Command:    self.Command,
 | 
					 | 
				
			||||||
		Created:    self.Created,
 | 
					 | 
				
			||||||
		Status:     self.Status,
 | 
					 | 
				
			||||||
		Ports:      displayablePorts(self.Ports),
 | 
					 | 
				
			||||||
		SizeRw:     self.SizeRw,
 | 
					 | 
				
			||||||
		SizeRootFs: self.SizeRootFs,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIContainersOld struct {
 | 
					 | 
				
			||||||
	ID         string `json:"Id"`
 | 
					 | 
				
			||||||
	Image      string
 | 
					 | 
				
			||||||
	Command    string
 | 
					 | 
				
			||||||
	Created    int64
 | 
					 | 
				
			||||||
	Status     string
 | 
					 | 
				
			||||||
	Ports      string
 | 
					 | 
				
			||||||
	SizeRw     int64
 | 
					 | 
				
			||||||
	SizeRootFs int64
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIID struct {
 | 
					 | 
				
			||||||
	ID string `json:"Id"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIRun struct {
 | 
					 | 
				
			||||||
	ID       string   `json:"Id"`
 | 
					 | 
				
			||||||
	Warnings []string `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIPort struct {
 | 
					 | 
				
			||||||
	PrivatePort int64
 | 
					 | 
				
			||||||
	PublicPort  int64
 | 
					 | 
				
			||||||
	Type        string
 | 
					 | 
				
			||||||
	IP          string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIVersion struct {
 | 
					 | 
				
			||||||
	Version   string
 | 
					 | 
				
			||||||
	GitCommit string `json:",omitempty"`
 | 
					 | 
				
			||||||
	GoVersion string `json:",omitempty"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIWait struct {
 | 
					 | 
				
			||||||
	StatusCode int
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIAuth struct {
 | 
					 | 
				
			||||||
	Status string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APIImageConfig struct {
 | 
					 | 
				
			||||||
	ID string `json:"Id"`
 | 
					 | 
				
			||||||
	*Config
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type APICopy struct {
 | 
					 | 
				
			||||||
	Resource string
 | 
					 | 
				
			||||||
	HostPath string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								api_unit_tests.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								api_unit_tests.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestJsonContentType(t *testing.T) {
 | 
				
			||||||
 | 
						if !matchesContentType("application/json", "application/json") {
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !matchesContentType("application/json; charset=utf-8", "application/json") {
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if matchesContentType("dockerapplication/json", "application/json") {
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -175,16 +175,17 @@ func Untar(archive io.Reader, path string, options *TarOptions) error {
 | 
				
			||||||
	buf := make([]byte, 10)
 | 
						buf := make([]byte, 10)
 | 
				
			||||||
	totalN := 0
 | 
						totalN := 0
 | 
				
			||||||
	for totalN < 10 {
 | 
						for totalN < 10 {
 | 
				
			||||||
		if n, err := archive.Read(buf[totalN:]); err != nil {
 | 
							n, err := archive.Read(buf[totalN:])
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
			if err == io.EOF {
 | 
								if err == io.EOF {
 | 
				
			||||||
				return fmt.Errorf("Tarball too short")
 | 
									return fmt.Errorf("Tarball too short")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			totalN += n
 | 
					 | 
				
			||||||
			utils.Debugf("[tar autodetect] n: %d", n)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							totalN += n
 | 
				
			||||||
 | 
							utils.Debugf("[tar autodetect] n: %d", n)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compression := DetectCompression(buf)
 | 
						compression := DetectCompression(buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	utils.Debugf("Archive compression detected: %s", compression.Extension())
 | 
						utils.Debugf("Archive compression detected: %s", compression.Extension())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,10 +196,9 @@ func Login(authConfig *AuthConfig, factory *utils.HTTPRequestFactory) (string, e
 | 
				
			||||||
		if loginAgainstOfficialIndex {
 | 
							if loginAgainstOfficialIndex {
 | 
				
			||||||
			return "", fmt.Errorf("Login: Your account hasn't been activated. " +
 | 
								return "", fmt.Errorf("Login: Your account hasn't been activated. " +
 | 
				
			||||||
				"Please check your e-mail for a confirmation link.")
 | 
									"Please check your e-mail for a confirmation link.")
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			return "", fmt.Errorf("Login: Your account hasn't been activated. " +
 | 
					 | 
				
			||||||
				"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return "", fmt.Errorf("Login: Your account hasn't been activated. " +
 | 
				
			||||||
 | 
								"Please see the documentation of the registry " + serverAddress + " for instructions how to activate it.")
 | 
				
			||||||
	} else if reqStatusCode == 400 {
 | 
						} else if reqStatusCode == 400 {
 | 
				
			||||||
		if string(reqBody) == "\"Username or email already exists\"" {
 | 
							if string(reqBody) == "\"Username or email already exists\"" {
 | 
				
			||||||
			req, err := factory.NewRequest("GET", serverAddress+"users/", nil)
 | 
								req, err := factory.NewRequest("GET", serverAddress+"users/", nil)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,8 @@
 | 
				
			||||||
package auth
 | 
					package auth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/rand"
 | 
					 | 
				
			||||||
	"encoding/hex"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,52 +26,6 @@ func TestEncodeAuth(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestLogin(t *testing.T) {
 | 
					 | 
				
			||||||
	os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
 | 
					 | 
				
			||||||
	defer os.Setenv("DOCKER_INDEX_URL", "")
 | 
					 | 
				
			||||||
	authConfig := &AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
 | 
					 | 
				
			||||||
	status, err := Login(authConfig, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if status != "Login Succeeded" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected status \"Login Succeeded\", found \"%s\" instead", status)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCreateAccount(t *testing.T) {
 | 
					 | 
				
			||||||
	os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
 | 
					 | 
				
			||||||
	defer os.Setenv("DOCKER_INDEX_URL", "")
 | 
					 | 
				
			||||||
	tokenBuffer := make([]byte, 16)
 | 
					 | 
				
			||||||
	_, err := rand.Read(tokenBuffer)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	token := hex.EncodeToString(tokenBuffer)[:12]
 | 
					 | 
				
			||||||
	username := "ut" + token
 | 
					 | 
				
			||||||
	authConfig := &AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
 | 
					 | 
				
			||||||
	status, err := Login(authConfig, nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	expectedStatus := "Account created. Please use the confirmation link we sent" +
 | 
					 | 
				
			||||||
		" to your e-mail to activate it."
 | 
					 | 
				
			||||||
	if status != expectedStatus {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	status, err = Login(authConfig, nil)
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected error but found nil instead")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	expectedError := "Login: Account is not Active"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !strings.Contains(err.Error(), expectedError) {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func setupTempConfigFile() (*ConfigFile, error) {
 | 
					func setupTempConfigFile() (*ConfigFile, error) {
 | 
				
			||||||
	root, err := ioutil.TempDir("", "docker-test-auth")
 | 
						root, err := ioutil.TempDir("", "docker-test-auth")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								commands.go
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								commands.go
									
										
									
									
									
								
							| 
						 | 
					@ -135,7 +135,7 @@ func (cli *DockerCli) CmdInsert(args ...string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mkBuildContext returns an archive of an empty context with the contents
 | 
					// mkBuildContext returns an archive of an empty context with the contents
 | 
				
			||||||
// of `dockerfile` at the path ./Dockerfile
 | 
					// of `dockerfile` at the path ./Dockerfile
 | 
				
			||||||
func mkBuildContext(dockerfile string, files [][2]string) (archive.Archive, error) {
 | 
					func MkBuildContext(dockerfile string, files [][2]string) (archive.Archive, error) {
 | 
				
			||||||
	buf := new(bytes.Buffer)
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
	tw := tar.NewWriter(buf)
 | 
						tw := tar.NewWriter(buf)
 | 
				
			||||||
	files = append(files, [2]string{"Dockerfile", dockerfile})
 | 
						files = append(files, [2]string{"Dockerfile", dockerfile})
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		context, err = mkBuildContext(string(dockerfile), nil)
 | 
							context, err = MkBuildContext(string(dockerfile), nil)
 | 
				
			||||||
	} else if utils.IsURL(cmd.Arg(0)) || utils.IsGIT(cmd.Arg(0)) {
 | 
						} else if utils.IsURL(cmd.Arg(0)) || utils.IsGIT(cmd.Arg(0)) {
 | 
				
			||||||
		isRemote = true
 | 
							isRemote = true
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -553,6 +553,9 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
 | 
				
			||||||
	utils.CatchAll(sigc)
 | 
						utils.CatchAll(sigc)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		for s := range sigc {
 | 
							for s := range sigc {
 | 
				
			||||||
 | 
								if s == syscall.SIGCHLD {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if _, _, err := cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%d", cid, s), nil); err != nil {
 | 
								if _, _, err := cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%d", cid, s), nil); err != nil {
 | 
				
			||||||
				utils.Debugf("Error sending signal: %s", err)
 | 
									utils.Debugf("Error sending signal: %s", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -2076,10 +2079,9 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if matchesContentType(resp.Header.Get("Content-Type"), "application/json") {
 | 
						if matchesContentType(resp.Header.Get("Content-Type"), "application/json") {
 | 
				
			||||||
		return utils.DisplayJSONMessagesStream(resp.Body, out)
 | 
							return utils.DisplayJSONMessagesStream(resp.Body, out)
 | 
				
			||||||
	} else {
 | 
						}
 | 
				
			||||||
		if _, err := io.Copy(out, resp.Body); err != nil {
 | 
						if _, err := io.Copy(out, resp.Body); err != nil {
 | 
				
			||||||
			return err
 | 
							return err
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										149
									
								
								config_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								config_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,149 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCompareConfig(t *testing.T) {
 | 
				
			||||||
 | 
						volumes1 := make(map[string]struct{})
 | 
				
			||||||
 | 
						volumes1["/test1"] = struct{}{}
 | 
				
			||||||
 | 
						config1 := Config{
 | 
				
			||||||
 | 
							Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "11111111",
 | 
				
			||||||
 | 
							Volumes:     volumes1,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config2 := Config{
 | 
				
			||||||
 | 
							Dns:         []string{"0.0.0.0", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "11111111",
 | 
				
			||||||
 | 
							Volumes:     volumes1,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config3 := Config{
 | 
				
			||||||
 | 
							Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "11111111",
 | 
				
			||||||
 | 
							Volumes:     volumes1,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config4 := Config{
 | 
				
			||||||
 | 
							Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "22222222",
 | 
				
			||||||
 | 
							Volumes:     volumes1,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						volumes2 := make(map[string]struct{})
 | 
				
			||||||
 | 
						volumes2["/test2"] = struct{}{}
 | 
				
			||||||
 | 
						config5 := Config{
 | 
				
			||||||
 | 
							Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "11111111",
 | 
				
			||||||
 | 
							Volumes:     volumes2,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if CompareConfig(&config1, &config2) {
 | 
				
			||||||
 | 
							t.Fatalf("CompareConfig should return false, Dns are different")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if CompareConfig(&config1, &config3) {
 | 
				
			||||||
 | 
							t.Fatalf("CompareConfig should return false, PortSpecs are different")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if CompareConfig(&config1, &config4) {
 | 
				
			||||||
 | 
							t.Fatalf("CompareConfig should return false, VolumesFrom are different")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if CompareConfig(&config1, &config5) {
 | 
				
			||||||
 | 
							t.Fatalf("CompareConfig should return false, Volumes are different")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !CompareConfig(&config1, &config1) {
 | 
				
			||||||
 | 
							t.Fatalf("CompareConfig should return true")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMergeConfig(t *testing.T) {
 | 
				
			||||||
 | 
						volumesImage := make(map[string]struct{})
 | 
				
			||||||
 | 
						volumesImage["/test1"] = struct{}{}
 | 
				
			||||||
 | 
						volumesImage["/test2"] = struct{}{}
 | 
				
			||||||
 | 
						configImage := &Config{
 | 
				
			||||||
 | 
							Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
				
			||||||
 | 
							PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
				
			||||||
 | 
							Env:         []string{"VAR1=1", "VAR2=2"},
 | 
				
			||||||
 | 
							VolumesFrom: "1111",
 | 
				
			||||||
 | 
							Volumes:     volumesImage,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						volumesUser := make(map[string]struct{})
 | 
				
			||||||
 | 
						volumesUser["/test3"] = struct{}{}
 | 
				
			||||||
 | 
						configUser := &Config{
 | 
				
			||||||
 | 
							Dns:       []string{"3.3.3.3"},
 | 
				
			||||||
 | 
							PortSpecs: []string{"3333:2222", "3333:3333"},
 | 
				
			||||||
 | 
							Env:       []string{"VAR2=3", "VAR3=3"},
 | 
				
			||||||
 | 
							Volumes:   volumesUser,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := MergeConfig(configUser, configImage); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(configUser.Dns) != 3 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, dns := range configUser.Dns {
 | 
				
			||||||
 | 
							if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
 | 
				
			||||||
 | 
								t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(configUser.ExposedPorts) != 3 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for portSpecs := range configUser.ExposedPorts {
 | 
				
			||||||
 | 
							if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
 | 
				
			||||||
 | 
								t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(configUser.Env) != 3 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, env := range configUser.Env {
 | 
				
			||||||
 | 
							if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
 | 
				
			||||||
 | 
								t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(configUser.Volumes) != 3 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for v := range configUser.Volumes {
 | 
				
			||||||
 | 
							if v != "/test1" && v != "/test2" && v != "/test3" {
 | 
				
			||||||
 | 
								t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if configUser.VolumesFrom != "1111" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ports, _, err := parsePortSpecs([]string{"0000"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						configImage2 := &Config{
 | 
				
			||||||
 | 
							ExposedPorts: ports,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := MergeConfig(configUser, configImage2); err != nil {
 | 
				
			||||||
 | 
							t.Error(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(configUser.ExposedPorts) != 4 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for portSpecs := range configUser.ExposedPorts {
 | 
				
			||||||
 | 
							if portSpecs.Port() != "0000" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
 | 
				
			||||||
 | 
								t.Fatalf("Expected 0000 or 1111 or 2222 or 3333, found %s", portSpecs)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										161
									
								
								container_unit_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								container_unit_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,161 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestParseLxcConfOpt(t *testing.T) {
 | 
				
			||||||
 | 
						opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, o := range opts {
 | 
				
			||||||
 | 
							k, v, err := parseLxcOpt(o)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if k != "lxc.utsname" {
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if v != "docker" {
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestParseNetworkOptsPrivateOnly(t *testing.T) {
 | 
				
			||||||
 | 
						ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(ports) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(ports))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(bindings) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(bindings))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for k := range ports {
 | 
				
			||||||
 | 
							if k.Proto() != "tcp" {
 | 
				
			||||||
 | 
								t.Logf("Expected tcp got %s", k.Proto())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if k.Port() != "80" {
 | 
				
			||||||
 | 
								t.Logf("Expected 80 got %s", k.Port())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							b, exists := bindings[k]
 | 
				
			||||||
 | 
							if !exists {
 | 
				
			||||||
 | 
								t.Log("Binding does not exist")
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(b) != 1 {
 | 
				
			||||||
 | 
								t.Logf("Expected 1 got %d", len(b))
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							s := b[0]
 | 
				
			||||||
 | 
							if s.HostPort != "" {
 | 
				
			||||||
 | 
								t.Logf("Expected \"\" got %s", s.HostPort)
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if s.HostIp != "192.168.1.100" {
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestParseNetworkOptsPublic(t *testing.T) {
 | 
				
			||||||
 | 
						ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(ports) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(ports))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(bindings) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(bindings))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for k := range ports {
 | 
				
			||||||
 | 
							if k.Proto() != "tcp" {
 | 
				
			||||||
 | 
								t.Logf("Expected tcp got %s", k.Proto())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if k.Port() != "80" {
 | 
				
			||||||
 | 
								t.Logf("Expected 80 got %s", k.Port())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							b, exists := bindings[k]
 | 
				
			||||||
 | 
							if !exists {
 | 
				
			||||||
 | 
								t.Log("Binding does not exist")
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(b) != 1 {
 | 
				
			||||||
 | 
								t.Logf("Expected 1 got %d", len(b))
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							s := b[0]
 | 
				
			||||||
 | 
							if s.HostPort != "8080" {
 | 
				
			||||||
 | 
								t.Logf("Expected 8080 got %s", s.HostPort)
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if s.HostIp != "192.168.1.100" {
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestParseNetworkOptsUdp(t *testing.T) {
 | 
				
			||||||
 | 
						ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(ports) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(ports))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(bindings) != 1 {
 | 
				
			||||||
 | 
							t.Logf("Expected 1 got %d", len(bindings))
 | 
				
			||||||
 | 
							t.FailNow()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for k := range ports {
 | 
				
			||||||
 | 
							if k.Proto() != "udp" {
 | 
				
			||||||
 | 
								t.Logf("Expected udp got %s", k.Proto())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if k.Port() != "6000" {
 | 
				
			||||||
 | 
								t.Logf("Expected 6000 got %s", k.Port())
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							b, exists := bindings[k]
 | 
				
			||||||
 | 
							if !exists {
 | 
				
			||||||
 | 
								t.Log("Binding does not exist")
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(b) != 1 {
 | 
				
			||||||
 | 
								t.Logf("Expected 1 got %d", len(b))
 | 
				
			||||||
 | 
								t.FailNow()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							s := b[0]
 | 
				
			||||||
 | 
							if s.HostPort != "" {
 | 
				
			||||||
 | 
								t.Logf("Expected \"\" got %s", s.HostPort)
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if s.HostIp != "192.168.1.100" {
 | 
				
			||||||
 | 
								t.Fail()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetFullName(t *testing.T) {
 | 
				
			||||||
 | 
						name, err := getFullName("testing")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if name != "/testing" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected /testing got %s", name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := getFullName(""); err == nil {
 | 
				
			||||||
 | 
							t.Fatal("Error should not be nil")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -192,7 +192,7 @@ if [ "$justTar" ]; then
 | 
				
			||||||
	sudo tar --numeric-owner -caf "$repo" .
 | 
						sudo tar --numeric-owner -caf "$repo" .
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
	# create the image (and tag $repo:$suite)
 | 
						# create the image (and tag $repo:$suite)
 | 
				
			||||||
	sudo tar --numeric-owner -c . | $docker import - $repo $suite
 | 
						sudo tar --numeric-owner -c . | $docker import - $repo:$suite
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	# test the image
 | 
						# test the image
 | 
				
			||||||
	$docker run -i -t $repo:$suite echo success
 | 
						$docker run -i -t $repo:$suite echo success
 | 
				
			||||||
| 
						 | 
					@ -202,25 +202,25 @@ else
 | 
				
			||||||
			Debian)
 | 
								Debian)
 | 
				
			||||||
				if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
 | 
									if [ "$suite" = "$debianStable" -o "$suite" = 'stable' ] && [ -r etc/debian_version ]; then
 | 
				
			||||||
					# tag latest
 | 
										# tag latest
 | 
				
			||||||
					$docker tag $repo:$suite $repo latest
 | 
										$docker tag $repo:$suite $repo:latest
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
					if [ -r etc/debian_version ]; then
 | 
										if [ -r etc/debian_version ]; then
 | 
				
			||||||
						# tag the specific debian release version (which is only reasonable to tag on debian stable)
 | 
											# tag the specific debian release version (which is only reasonable to tag on debian stable)
 | 
				
			||||||
						ver=$(cat etc/debian_version)
 | 
											ver=$(cat etc/debian_version)
 | 
				
			||||||
						$docker tag $repo:$suite $repo $ver
 | 
											$docker tag $repo:$suite $repo:$ver
 | 
				
			||||||
					fi
 | 
										fi
 | 
				
			||||||
				fi
 | 
									fi
 | 
				
			||||||
				;;
 | 
									;;
 | 
				
			||||||
			Ubuntu)
 | 
								Ubuntu)
 | 
				
			||||||
				if [ "$suite" = "$ubuntuLatestLTS" ]; then
 | 
									if [ "$suite" = "$ubuntuLatestLTS" ]; then
 | 
				
			||||||
					# tag latest
 | 
										# tag latest
 | 
				
			||||||
					$docker tag $repo:$suite $repo latest
 | 
										$docker tag $repo:$suite $repo:latest
 | 
				
			||||||
				fi
 | 
									fi
 | 
				
			||||||
				if [ -r etc/lsb-release ]; then
 | 
									if [ -r etc/lsb-release ]; then
 | 
				
			||||||
					lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
 | 
										lsbRelease="$(. etc/lsb-release && echo "$DISTRIB_RELEASE")"
 | 
				
			||||||
					if [ "$lsbRelease" ]; then
 | 
										if [ "$lsbRelease" ]; then
 | 
				
			||||||
						# tag specific Ubuntu version number, if available (12.04, etc.)
 | 
											# tag specific Ubuntu version number, if available (12.04, etc.)
 | 
				
			||||||
						$docker tag $repo:$suite $repo $lsbRelease
 | 
											$docker tag $repo:$suite $repo:$lsbRelease
 | 
				
			||||||
					fi
 | 
										fi
 | 
				
			||||||
				fi
 | 
									fi
 | 
				
			||||||
				;;
 | 
									;;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ help:
 | 
				
			||||||
#	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
 | 
					#	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
 | 
				
			||||||
#	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
 | 
					#	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
 | 
				
			||||||
#	@echo "  text       to make text files"
 | 
					#	@echo "  text       to make text files"
 | 
				
			||||||
#	@echo "  man        to make manual pages"
 | 
						@echo "  man        to make a manual page"
 | 
				
			||||||
#	@echo "  texinfo    to make Texinfo files"
 | 
					#	@echo "  texinfo    to make Texinfo files"
 | 
				
			||||||
#	@echo "  info       to make Texinfo files and run them through makeinfo"
 | 
					#	@echo "  info       to make Texinfo files and run them through makeinfo"
 | 
				
			||||||
#	@echo "  gettext    to make PO message catalogs"
 | 
					#	@echo "  gettext    to make PO message catalogs"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,2 +1,2 @@
 | 
				
			||||||
Sphinx==1.1.3
 | 
					Sphinx==1.1.3
 | 
				
			||||||
sphinxcontrib-httpdomain==1.1.8
 | 
					sphinxcontrib-httpdomain==1.1.9
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,9 +13,12 @@ Docker Remote API v1.7
 | 
				
			||||||
1. Brief introduction
 | 
					1. Brief introduction
 | 
				
			||||||
=====================
 | 
					=====================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- The Remote API is replacing rcli
 | 
					- The Remote API has replaced rcli
 | 
				
			||||||
- Default port in the docker daemon is 4243
 | 
					- The daemon listens on ``unix:///var/run/docker.sock``, but you can
 | 
				
			||||||
- The API tends to be REST, but for some complex commands, like attach or pull, the HTTP connection is hijacked to transport stdout stdin and stderr
 | 
					  :ref:`bind_docker`.
 | 
				
			||||||
 | 
					- The API tends to be REST, but for some complex commands, like
 | 
				
			||||||
 | 
					  ``attach`` or ``pull``, the HTTP connection is hijacked to transport
 | 
				
			||||||
 | 
					  ``stdout, stdin`` and ``stderr``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. Endpoints
 | 
					2. Endpoints
 | 
				
			||||||
============
 | 
					============
 | 
				
			||||||
| 
						 | 
					@ -690,10 +693,12 @@ Create an image
 | 
				
			||||||
        :query repo: repository
 | 
					        :query repo: repository
 | 
				
			||||||
	:query tag: tag
 | 
						:query tag: tag
 | 
				
			||||||
	:query registry: the registry to pull from
 | 
						:query registry: the registry to pull from
 | 
				
			||||||
 | 
						:reqheader X-Registry-Auth: base64-encoded AuthConfig object
 | 
				
			||||||
        :statuscode 200: no error
 | 
					        :statuscode 200: no error
 | 
				
			||||||
        :statuscode 500: server error
 | 
					        :statuscode 500: server error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Insert a file in an image
 | 
					Insert a file in an image
 | 
				
			||||||
*************************
 | 
					*************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -835,18 +840,16 @@ Push an image on the registry
 | 
				
			||||||
    HTTP/1.1 200 OK
 | 
					    HTTP/1.1 200 OK
 | 
				
			||||||
    Content-Type: application/json
 | 
					    Content-Type: application/json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   {"status":"Pushing..."}
 | 
					    {"status":"Pushing..."}
 | 
				
			||||||
   {"status":"Pushing", "progress":"1/? (n/a)"}
 | 
					    {"status":"Pushing", "progress":"1/? (n/a)"}
 | 
				
			||||||
   {"error":"Invalid..."}
 | 
					    {"error":"Invalid..."}
 | 
				
			||||||
   ...
 | 
					    ...
 | 
				
			||||||
 | 
					 | 
				
			||||||
	The ``X-Registry-Auth`` header can be used to include a
 | 
					 | 
				
			||||||
	base64-encoded AuthConfig object.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
   :query registry: the registry you wan to push, optional
 | 
					   :query registry: the registry you wan to push, optional
 | 
				
			||||||
 | 
					   :reqheader X-Registry-Auth: include a base64-encoded AuthConfig object.
 | 
				
			||||||
   :statuscode 200: no error
 | 
					   :statuscode 200: no error
 | 
				
			||||||
        :statuscode 404: no such image
 | 
					   :statuscode 404: no such image
 | 
				
			||||||
        :statuscode 500: server error
 | 
					   :statuscode 500: server error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tag an image into a repository
 | 
					Tag an image into a repository
 | 
				
			||||||
| 
						 | 
					@ -959,9 +962,9 @@ Search images
 | 
				
			||||||
	   ...
 | 
						   ...
 | 
				
			||||||
	   ]
 | 
						   ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	   :query term: term to search
 | 
						:query term: term to search
 | 
				
			||||||
	   :statuscode 200: no error
 | 
						:statuscode 200: no error
 | 
				
			||||||
	   :statuscode 500: server error
 | 
						:statuscode 500: server error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2.3 Misc
 | 
					2.3 Misc
 | 
				
			||||||
| 
						 | 
					@ -991,18 +994,22 @@ Build an image from Dockerfile via stdin
 | 
				
			||||||
      {{ STREAM }}
 | 
					      {{ STREAM }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       The stream must be a tar archive compressed with one of the following algorithms:
 | 
					   The stream must be a tar archive compressed with one of the
 | 
				
			||||||
       identity (no compression), gzip, bzip2, xz. The archive must include a file called
 | 
					   following algorithms: identity (no compression), gzip, bzip2,
 | 
				
			||||||
       `Dockerfile` at its root. It may include any number of other files, which will be
 | 
					   xz. 
 | 
				
			||||||
       accessible in the build context (See the ADD build command).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
       The Content-type header should be set to "application/tar".
 | 
					   The archive must include a file called ``Dockerfile`` at its
 | 
				
			||||||
 | 
					   root. It may include any number of other files, which will be
 | 
				
			||||||
 | 
					   accessible in the build context (See the :ref:`ADD build command
 | 
				
			||||||
 | 
					   <dockerbuilder>`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   :query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
 | 
				
			||||||
 | 
					   :query q: suppress verbose build output
 | 
				
			||||||
 | 
					   :query nocache: do not use the cache when building the image
 | 
				
			||||||
 | 
					   :reqheader Content-type: should be set to ``"application/tar"``.
 | 
				
			||||||
 | 
					   :statuscode 200: no error
 | 
				
			||||||
 | 
					   :statuscode 500: server error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	:query t: repository name (and optionally a tag) to be applied to the resulting image in case of success
 | 
					 | 
				
			||||||
	:query q: suppress verbose build output
 | 
					 | 
				
			||||||
    :query nocache: do not use the cache when building the image
 | 
					 | 
				
			||||||
	:statuscode 200: no error
 | 
					 | 
				
			||||||
    :statuscode 500: server error
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Check auth configuration
 | 
					Check auth configuration
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -231,9 +231,33 @@ Full -run example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
::
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Usage: docker diff CONTAINER [OPTIONS]
 | 
					    Usage: docker diff CONTAINER
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					    List the changed files and directories in a container's filesystem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Inspect changes on a container's filesystem
 | 
					There are 3 events that are listed in the 'diff':
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. ```A``` - Add
 | 
				
			||||||
 | 
					2. ```D``` - Delete
 | 
				
			||||||
 | 
					3. ```C``` - Change
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$ sudo docker diff 7bb0e258aefe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						C /dev
 | 
				
			||||||
 | 
						A /dev/kmsg
 | 
				
			||||||
 | 
						C /etc
 | 
				
			||||||
 | 
						A /etc/mtab
 | 
				
			||||||
 | 
						A /go
 | 
				
			||||||
 | 
						A /go/src
 | 
				
			||||||
 | 
						A /go/src/github.com
 | 
				
			||||||
 | 
						A /go/src/github.com/dotcloud
 | 
				
			||||||
 | 
						A /go/src/github.com/dotcloud/docker
 | 
				
			||||||
 | 
						A /go/src/github.com/dotcloud/docker/.git
 | 
				
			||||||
 | 
						....
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _cli_events:
 | 
					.. _cli_events:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -323,6 +347,40 @@ Show events in the past from a specified time
 | 
				
			||||||
      -notrunc=false: Don't truncate output
 | 
					      -notrunc=false: Don't truncate output
 | 
				
			||||||
      -q=false: only show numeric IDs
 | 
					      -q=false: only show numeric IDs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To see how the docker:latest image was built:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$ docker history docker
 | 
				
			||||||
 | 
						ID                  CREATED             CREATED BY
 | 
				
			||||||
 | 
						docker:latest       19 hours ago        /bin/sh -c #(nop) ADD . in /go/src/github.com/dotcloud/docker
 | 
				
			||||||
 | 
						cf5f2467662d        2 weeks ago         /bin/sh -c #(nop) ENTRYPOINT ["hack/dind"]
 | 
				
			||||||
 | 
						3538fbe372bf        2 weeks ago         /bin/sh -c #(nop) WORKDIR /go/src/github.com/dotcloud/docker
 | 
				
			||||||
 | 
						7450f65072e5        2 weeks ago         /bin/sh -c #(nop) VOLUME /var/lib/docker
 | 
				
			||||||
 | 
						b79d62b97328        2 weeks ago         /bin/sh -c apt-get install -y -q lxc
 | 
				
			||||||
 | 
						36714852a550        2 weeks ago         /bin/sh -c apt-get install -y -q iptables
 | 
				
			||||||
 | 
						8c4c706df1d6        2 weeks ago         /bin/sh -c /bin/echo -e '[default]\naccess_key=$AWS_ACCESS_KEY\nsecret_key=$AWS_SECRET_KEYn' > /.s3cfg
 | 
				
			||||||
 | 
						b89989433c48        2 weeks ago         /bin/sh -c pip install python-magic
 | 
				
			||||||
 | 
						a23e640d85b5        2 weeks ago         /bin/sh -c pip install s3cmd
 | 
				
			||||||
 | 
						41f54fec7e79        2 weeks ago         /bin/sh -c apt-get install -y -q python-pip
 | 
				
			||||||
 | 
						d9bc04add907        2 weeks ago         /bin/sh -c apt-get install -y -q reprepro dpkg-sig
 | 
				
			||||||
 | 
						e74f4760fa70        2 weeks ago         /bin/sh -c gem install --no-rdoc --no-ri fpm
 | 
				
			||||||
 | 
						1e43224726eb        2 weeks ago         /bin/sh -c apt-get install -y -q ruby1.9.3 rubygems libffi-dev
 | 
				
			||||||
 | 
						460953ae9d7f        2 weeks ago         /bin/sh -c #(nop) ENV GOPATH=/go:/go/src/github.com/dotcloud/docker/vendor
 | 
				
			||||||
 | 
						8b63eb1d666b        2 weeks ago         /bin/sh -c #(nop) ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/goroot/bin
 | 
				
			||||||
 | 
						3087f3bcedf2        2 weeks ago         /bin/sh -c #(nop) ENV GOROOT=/goroot
 | 
				
			||||||
 | 
						635840d198e5        2 weeks ago         /bin/sh -c cd /goroot/src && ./make.bash
 | 
				
			||||||
 | 
						439f4a0592ba        2 weeks ago         /bin/sh -c curl -s https://go.googlecode.com/files/go1.1.2.src.tar.gz | tar -v -C / -xz && mv /go /goroot
 | 
				
			||||||
 | 
						13967ed36e93        2 weeks ago         /bin/sh -c #(nop) ENV CGO_ENABLED=0
 | 
				
			||||||
 | 
						bf7424458437        2 weeks ago         /bin/sh -c apt-get install -y -q build-essential
 | 
				
			||||||
 | 
						a89ec997c3bf        2 weeks ago         /bin/sh -c apt-get install -y -q mercurial
 | 
				
			||||||
 | 
						b9f165c6e749        2 weeks ago         /bin/sh -c apt-get install -y -q git
 | 
				
			||||||
 | 
						17a64374afa7        2 weeks ago         /bin/sh -c apt-get install -y -q curl
 | 
				
			||||||
 | 
						d5e85dc5b1d8        2 weeks ago         /bin/sh -c apt-get update
 | 
				
			||||||
 | 
						13e642467c11        2 weeks ago         /bin/sh -c echo 'deb http://archive.ubuntu.com/ubuntu precise main universe' > /etc/apt/sources.list
 | 
				
			||||||
 | 
						ae6dde92a94e        2 weeks ago         /bin/sh -c #(nop) MAINTAINER Solomon Hykes <solomon@dotcloud.com>
 | 
				
			||||||
 | 
						ubuntu:12.04        6 months ago 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _cli_images:
 | 
					.. _cli_images:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``images``
 | 
					``images``
 | 
				
			||||||
| 
						 | 
					@ -435,6 +493,21 @@ might not get preserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Display system-wide information.
 | 
					    Display system-wide information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$ sudo docker info
 | 
				
			||||||
 | 
						Containers: 292
 | 
				
			||||||
 | 
						Images: 194
 | 
				
			||||||
 | 
						Debug mode (server): false
 | 
				
			||||||
 | 
						Debug mode (client): false
 | 
				
			||||||
 | 
						Fds: 22
 | 
				
			||||||
 | 
						Goroutines: 67
 | 
				
			||||||
 | 
						LXC Version: 0.9.0
 | 
				
			||||||
 | 
						EventsListeners: 115
 | 
				
			||||||
 | 
						Kernel Version: 3.8.0-33-generic
 | 
				
			||||||
 | 
						WARNING: No swap limit support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _cli_insert:
 | 
					.. _cli_insert:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``insert``
 | 
					``insert``
 | 
				
			||||||
| 
						 | 
					@ -772,6 +845,13 @@ id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in
 | 
				
			||||||
read-only or read-write mode, respectively. By default, the volumes are mounted
 | 
					read-only or read-write mode, respectively. By default, the volumes are mounted
 | 
				
			||||||
in the same mode (rw or ro) as the reference container.
 | 
					in the same mode (rw or ro) as the reference container.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Known Issues (run -volumes-from)
 | 
				
			||||||
 | 
					~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
 | 
				
			||||||
 | 
					  could indicate a permissions problem with AppArmor. Please see the
 | 
				
			||||||
 | 
					  issue for a workaround.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _cli_search:
 | 
					.. _cli_search:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``search``
 | 
					``search``
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,7 @@ latex_documents = [
 | 
				
			||||||
# One entry per manual page. List of tuples
 | 
					# One entry per manual page. List of tuples
 | 
				
			||||||
# (source start file, name, description, authors, manual section).
 | 
					# (source start file, name, description, authors, manual section).
 | 
				
			||||||
man_pages = [
 | 
					man_pages = [
 | 
				
			||||||
    ('toctree', 'docker', u'Docker Documentation',
 | 
					    ('commandline/cli', 'docker', u'Docker Documentation',
 | 
				
			||||||
     [u'Team Docker'], 1)
 | 
					     [u'Team Docker'], 1)
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ Note that we're marking ``/var/lib/couchdb`` as a data volume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
 | 
					    COUCH1=$(sudo docker run -d -p 5984 -v /var/lib/couchdb shykes/couchdb:2013-05-03)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Add data to the first database
 | 
					Add data to the first database
 | 
				
			||||||
------------------------------
 | 
					------------------------------
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ replace ``localhost`` with the public IP of your Docker host.
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HOST=localhost
 | 
					    HOST=localhost
 | 
				
			||||||
    URL="http://$HOST:$(sudo docker port $COUCH1 5984)/_utils/"
 | 
					    URL="http://$HOST:$(sudo docker port $COUCH1 5984 | grep -Po '\d+$')/_utils/"
 | 
				
			||||||
    echo "Navigate to $URL in your browser, and use the couch interface to add data"
 | 
					    echo "Navigate to $URL in your browser, and use the couch interface to add data"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Create second database
 | 
					Create second database
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ This time, we're requesting shared access to ``$COUCH1``'s volumes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
 | 
					    COUCH2=$(sudo docker run -d -p 5984 -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Browse data on the second database
 | 
					Browse data on the second database
 | 
				
			||||||
----------------------------------
 | 
					----------------------------------
 | 
				
			||||||
| 
						 | 
					@ -49,7 +49,7 @@ Browse data on the second database
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    HOST=localhost
 | 
					    HOST=localhost
 | 
				
			||||||
    URL="http://$HOST:$(sudo docker port $COUCH2 5984)/_utils/"
 | 
					    URL="http://$HOST:$(sudo docker port $COUCH2 5984 | grep -Po '\d+$')/_utils/"
 | 
				
			||||||
    echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
 | 
					    echo "Navigate to $URL in your browser. You should see the same data as in the first database"'!'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Congratulations, you are now running two Couchdb containers, completely
 | 
					Congratulations, you are now running two Couchdb containers, completely
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    This example assumes you have Docker running in daemon mode. For more information please see :ref:`running_examples`
 | 
					    * This example assumes you have Docker running in daemon mode. For
 | 
				
			||||||
 | 
					      more information please see :ref:`running_examples`.
 | 
				
			||||||
 | 
					    * **If you don't like sudo** then see :ref:`dockergroup`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,10 +127,12 @@ Check the logs make sure it is working correctly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sudo docker attach $CONTAINER_ID
 | 
					    sudo docker attach $CONTAINER_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Attach to the container to see the results in realtime.
 | 
					Attach to the container to see the results in real-time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **"docker attach**" This will allow us to attach to a background
 | 
					- **"docker attach**" This will allow us to attach to a background
 | 
				
			||||||
  process to see what is going on.
 | 
					  process to see what is going on.
 | 
				
			||||||
 | 
					- **"-sig-proxy=true"** Proxify all received signal to the process
 | 
				
			||||||
 | 
					  (even in non-tty mode)
 | 
				
			||||||
- **$CONTAINER_ID** The Id of the container we want to attach too.
 | 
					- **$CONTAINER_ID** The Id of the container we want to attach too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Exit from the container attachment by pressing Control-C.
 | 
					Exit from the container attachment by pressing Control-C.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,11 +39,12 @@ container. The ``BUILD_JOB`` environment variable will be set with the new conta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sudo docker attach $BUILD_JOB
 | 
					    sudo docker attach -sig-proxy=false $BUILD_JOB
 | 
				
			||||||
    [...]
 | 
					    [...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
While this container is running, we can attach to the new container to
 | 
					While this container is running, we can attach to the new container to
 | 
				
			||||||
see what is going on. You can use Ctrl-C to disconnect.
 | 
					see what is going on. The flag ``-sig-proxy`` set as ``false`` allows you to connect and
 | 
				
			||||||
 | 
					disconnect (Ctrl-C) to it without stopping the container.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ with your own user name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sudo docker build -t <your username>/redis
 | 
					    sudo docker build -t <your username>/redis .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Run the service
 | 
					Run the service
 | 
				
			||||||
---------------
 | 
					---------------
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,7 @@ of our ``redis`` container.
 | 
				
			||||||
    DB_PORT_6379_TCP_ADDR=172.17.0.33
 | 
					    DB_PORT_6379_TCP_ADDR=172.17.0.33
 | 
				
			||||||
    DB_PORT_6379_TCP_PROTO=tcp
 | 
					    DB_PORT_6379_TCP_PROTO=tcp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We can see that we've got a small list of environmental varaibles prefixed with ``DB``. 
 | 
					We can see that we've got a small list of environment variables prefixed with ``DB``.
 | 
				
			||||||
The ``DB`` comes from the link alias specified when we launched the container. Let's use 
 | 
					The ``DB`` comes from the link alias specified when we launched the container. Let's use 
 | 
				
			||||||
the ``DB_PORT_6379_TCP_ADDR`` variable to connect to our Redis container.
 | 
					the ``DB_PORT_6379_TCP_ADDR`` variable to connect to our Redis container.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,9 +12,9 @@ SSH Daemon Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Video:**
 | 
					**Video:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
I've create a little screencast to show how to create a SSHd service
 | 
					I've created a little screencast to show how to create an SSHd service
 | 
				
			||||||
and connect to it. It is something like 11 minutes and not entirely
 | 
					and connect to it. It is something like 11 minutes and not entirely
 | 
				
			||||||
smooth, but gives you a good idea.
 | 
					smooth, but it gives you a good idea.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
   This screencast was created before Docker version 0.5.2, so the
 | 
					   This screencast was created before Docker version 0.5.2, so the
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,11 +19,12 @@ Contents:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   ubuntulinux
 | 
					   ubuntulinux
 | 
				
			||||||
   binaries
 | 
					   binaries
 | 
				
			||||||
 | 
					   security
 | 
				
			||||||
 | 
					   upgrading
 | 
				
			||||||
 | 
					   kernel
 | 
				
			||||||
   vagrant
 | 
					   vagrant
 | 
				
			||||||
   windows
 | 
					   windows
 | 
				
			||||||
   amazon
 | 
					   amazon
 | 
				
			||||||
   rackspace
 | 
					   rackspace
 | 
				
			||||||
   archlinux
 | 
					   archlinux
 | 
				
			||||||
   gentoolinux
 | 
					   gentoolinux
 | 
				
			||||||
   upgrading
 | 
					 | 
				
			||||||
   kernel
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ If you cannot or do not want to use the "official" kernels,
 | 
				
			||||||
here is some technical background about the features (both optional and
 | 
					here is some technical background about the features (both optional and
 | 
				
			||||||
mandatory) that docker needs to run successfully.
 | 
					mandatory) that docker needs to run successfully.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Linux version 3.8 or above
 | 
					Linux version 3.8 or above
 | 
				
			||||||
--------------------------
 | 
					--------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +40,15 @@ The symptoms include:
 | 
				
			||||||
- kernel crash causing the machine to freeze for a few minutes, or even
 | 
					- kernel crash causing the machine to freeze for a few minutes, or even
 | 
				
			||||||
  completely.
 | 
					  completely.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Additionally, kernels prior 3.4 did not implement ``reboot_pid_ns``,
 | 
				
			||||||
 | 
					which means that the ``reboot()`` syscall could reboot the host machine,
 | 
				
			||||||
 | 
					instead of terminating the container. To work around that problem,
 | 
				
			||||||
 | 
					LXC userland tools (since version 0.8) automatically drop the ``SYS_BOOT``
 | 
				
			||||||
 | 
					capability when necessary. Still, if you run a pre-3.4 kernel with pre-0.8
 | 
				
			||||||
 | 
					LXC tools, be aware that containers can reboot the whole host! This is
 | 
				
			||||||
 | 
					not something that Docker wants to address in the short term, since you
 | 
				
			||||||
 | 
					shouldn't use kernels prior 3.8 with Docker anyway.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
While it is still possible to use older kernels for development, it is
 | 
					While it is still possible to use older kernels for development, it is
 | 
				
			||||||
really not advised to do so.
 | 
					really not advised to do so.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										267
									
								
								docs/sources/installation/security.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								docs/sources/installation/security.rst
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,267 @@
 | 
				
			||||||
 | 
					:title: Docker Security
 | 
				
			||||||
 | 
					:description: Review of the Docker Daemon attack surface
 | 
				
			||||||
 | 
					:keywords: Docker, Docker documentation, security
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _dockersecurity:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Docker Security
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *Adapted from* `Containers & Docker: How Secure are They? <blogsecurity>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There are three major areas to consider when reviewing Docker security:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* the intrinsic security of containers, as implemented by kernel
 | 
				
			||||||
 | 
					  namespaces and cgroups;
 | 
				
			||||||
 | 
					* the attack surface of the Docker daemon itself;
 | 
				
			||||||
 | 
					* the "hardening" security features of the kernel and how they
 | 
				
			||||||
 | 
					  interact with containers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Kernel Namespaces
 | 
				
			||||||
 | 
					-----------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Docker containers are essentially LXC containers, and they come with
 | 
				
			||||||
 | 
					the same security features. When you start a container with ``docker
 | 
				
			||||||
 | 
					run``, behind the scenes Docker uses ``lxc-start`` to execute the
 | 
				
			||||||
 | 
					Docker container. This creates a set of namespaces and control groups
 | 
				
			||||||
 | 
					for the container. Those namespaces and control groups are not created
 | 
				
			||||||
 | 
					by Docker itself, but by ``lxc-start``. This means that as the LXC
 | 
				
			||||||
 | 
					userland tools evolve (and provide additional namespaces and isolation
 | 
				
			||||||
 | 
					features), Docker will automatically make use of them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Namespaces provide the first and most straightforward form of
 | 
				
			||||||
 | 
					isolation**: processes running within a container cannot see, and even
 | 
				
			||||||
 | 
					less affect, processes running in another container, or in the host
 | 
				
			||||||
 | 
					system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Each container also gets its own network stack**, meaning that a
 | 
				
			||||||
 | 
					container doesn’t get a privileged access to the sockets or interfaces
 | 
				
			||||||
 | 
					of another container. Of course, if the host system is setup
 | 
				
			||||||
 | 
					accordingly, containers can interact with each other through their
 | 
				
			||||||
 | 
					respective network interfaces — just like they can interact with
 | 
				
			||||||
 | 
					external hosts. When you specify public ports for your containers or
 | 
				
			||||||
 | 
					use :ref:`links <working_with_links_names>` then IP traffic is allowed
 | 
				
			||||||
 | 
					between containers. They can ping each other, send/receive UDP
 | 
				
			||||||
 | 
					packets, and establish TCP connections, but that can be restricted if
 | 
				
			||||||
 | 
					necessary. From a network architecture point of view, all containers
 | 
				
			||||||
 | 
					on a given Docker host are sitting on bridge interfaces. This means
 | 
				
			||||||
 | 
					that they are just like physical machines connected through a common
 | 
				
			||||||
 | 
					Ethernet switch; no more, no less.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					How mature is the code providing kernel namespaces and private
 | 
				
			||||||
 | 
					networking?  Kernel namespaces were introduced `between kernel version
 | 
				
			||||||
 | 
					2.6.15 and 2.6.26
 | 
				
			||||||
 | 
					<http://lxc.sourceforge.net/index.php/about/kernel-namespaces/>`_. This
 | 
				
			||||||
 | 
					means that since July 2008 (date of the 2.6.26 release, now 5 years
 | 
				
			||||||
 | 
					ago), namespace code has been exercised and scrutinized on a large
 | 
				
			||||||
 | 
					number of production systems. And there is more: the design and
 | 
				
			||||||
 | 
					inspiration for the namespaces code are even older. Namespaces are
 | 
				
			||||||
 | 
					actually an effort to reimplement the features of `OpenVZ
 | 
				
			||||||
 | 
					<http://en.wikipedia.org/wiki/OpenVZ>`_ in such a way that they could
 | 
				
			||||||
 | 
					be merged within the mainstream kernel. And OpenVZ was initially
 | 
				
			||||||
 | 
					released in 2005, so both the design and the implementation are
 | 
				
			||||||
 | 
					pretty mature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Control Groups
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Control Groups are the other key component of Linux Containers. They
 | 
				
			||||||
 | 
					implement resource accounting and limiting. They provide a lot of very
 | 
				
			||||||
 | 
					useful metrics, but they also help to ensure that each container gets
 | 
				
			||||||
 | 
					its fair share of memory, CPU, disk I/O; and, more importantly, that a
 | 
				
			||||||
 | 
					single container cannot bring the system down by exhausting one of
 | 
				
			||||||
 | 
					those resources.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					So while they do not play a role in preventing one container from
 | 
				
			||||||
 | 
					accessing or affecting the data and processes of another container,
 | 
				
			||||||
 | 
					they are essential to fend off some denial-of-service attacks. They
 | 
				
			||||||
 | 
					are particularly important on multi-tenant platforms, like public and
 | 
				
			||||||
 | 
					private PaaS, to guarantee a consistent uptime (and performance) even
 | 
				
			||||||
 | 
					when some applications start to misbehave.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Control Groups have been around for a while as well: the code was
 | 
				
			||||||
 | 
					started in 2006, and initially merged in kernel 2.6.24.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Docker Daemon Attack Surface
 | 
				
			||||||
 | 
					----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Running containers (and applications) with Docker implies running the
 | 
				
			||||||
 | 
					Docker daemon. This daemon currently requires root privileges, and you
 | 
				
			||||||
 | 
					should therefore be aware of some important details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First of all, **only trusted users should be allowed to control your
 | 
				
			||||||
 | 
					Docker daemon**. This is a direct consequence of some powerful Docker
 | 
				
			||||||
 | 
					features. Specifically, Docker allows you to share a directory between
 | 
				
			||||||
 | 
					the Docker host and a guest container; and it allows you to do so
 | 
				
			||||||
 | 
					without limiting the access rights of the container. This means that
 | 
				
			||||||
 | 
					you can start a container where the ``/host`` directory will be the
 | 
				
			||||||
 | 
					``/`` directory on your host; and the container will be able to alter
 | 
				
			||||||
 | 
					your host filesystem without any restriction. This sounds crazy? Well,
 | 
				
			||||||
 | 
					you have to know that **all virtualization systems allowing filesystem
 | 
				
			||||||
 | 
					resource sharing behave the same way**. Nothing prevents you from
 | 
				
			||||||
 | 
					sharing your root filesystem (or even your root block device) with a
 | 
				
			||||||
 | 
					virtual machine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This has a strong security implication: if you instrument Docker from
 | 
				
			||||||
 | 
					e.g. a web server to provision containers through an API, you should
 | 
				
			||||||
 | 
					be even more careful than usual with parameter checking, to make sure
 | 
				
			||||||
 | 
					that a malicious user cannot pass crafted parameters causing Docker to
 | 
				
			||||||
 | 
					create arbitrary containers.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For this reason, the REST API endpoint (used by the Docker CLI to
 | 
				
			||||||
 | 
					communicate with the Docker daemon) changed in Docker 0.5.2, and now
 | 
				
			||||||
 | 
					uses a UNIX socket instead of a TCP socket bound on 127.0.0.1 (the
 | 
				
			||||||
 | 
					latter being prone to cross-site-scripting attacks if you happen to
 | 
				
			||||||
 | 
					run Docker directly on your local machine, outside of a VM). You can
 | 
				
			||||||
 | 
					then use traditional UNIX permission checks to limit access to the
 | 
				
			||||||
 | 
					control socket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also expose the REST API over HTTP if you explicitly decide
 | 
				
			||||||
 | 
					so. However, if you do that, being aware of the abovementioned
 | 
				
			||||||
 | 
					security implication, you should ensure that it will be reachable
 | 
				
			||||||
 | 
					only from a trusted network or VPN; or protected with e.g. ``stunnel``
 | 
				
			||||||
 | 
					and client SSL certificates.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Recent improvements in Linux namespaces will soon allow to run
 | 
				
			||||||
 | 
					full-featured containers without root privileges, thanks to the new
 | 
				
			||||||
 | 
					user namespace. This is covered in detail `here
 | 
				
			||||||
 | 
					<http://s3hh.wordpress.com/2013/07/19/creating-and-using-containers-without-privilege/>`_. Moreover,
 | 
				
			||||||
 | 
					this will solve the problem caused by sharing filesystems between host
 | 
				
			||||||
 | 
					and guest, since the user namespace allows users within containers
 | 
				
			||||||
 | 
					(including the root user) to be mapped to other users in the host
 | 
				
			||||||
 | 
					system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The end goal for Docker is therefore to implement two additional
 | 
				
			||||||
 | 
					security improvements:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* map the root user of a container to a non-root user of the Docker
 | 
				
			||||||
 | 
					  host, to mitigate the effects of a container-to-host privilege
 | 
				
			||||||
 | 
					  escalation;
 | 
				
			||||||
 | 
					* allow the Docker daemon to run without root privileges, and delegate
 | 
				
			||||||
 | 
					  operations requiring those privileges to well-audited sub-processes,
 | 
				
			||||||
 | 
					  each with its own (very limited) scope: virtual network setup,
 | 
				
			||||||
 | 
					  filesystem management, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Finally, if you run Docker on a server, it is recommended to run
 | 
				
			||||||
 | 
					exclusively Docker in the server, and move all other services within
 | 
				
			||||||
 | 
					containers controlled by Docker. Of course, it is fine to keep your
 | 
				
			||||||
 | 
					favorite admin tools (probably at least an SSH server), as well as
 | 
				
			||||||
 | 
					existing monitoring/supervision processes (e.g. NRPE, collectd, etc).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Linux Kernel Capabilities
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default, Docker starts containers with a very restricted set of
 | 
				
			||||||
 | 
					capabilities. What does that mean?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Capabilities turn the binary "root/non-root" dichotomy into a
 | 
				
			||||||
 | 
					fine-grained access control system. Processes (like web servers) that
 | 
				
			||||||
 | 
					just need to bind on a port below 1024 do not have to run as root:
 | 
				
			||||||
 | 
					they can just be granted the ``net_bind_service`` capability
 | 
				
			||||||
 | 
					instead. And there are many other capabilities, for almost all the
 | 
				
			||||||
 | 
					specific areas where root privileges are usually needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This means a lot for container security; let’s see why!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Your average server (bare metal or virtual machine) needs to run a
 | 
				
			||||||
 | 
					bunch of processes as root. Those typically include SSH, cron,
 | 
				
			||||||
 | 
					syslogd; hardware management tools (to e.g. load modules), network
 | 
				
			||||||
 | 
					configuration tools (to handle e.g. DHCP, WPA, or VPNs), and much
 | 
				
			||||||
 | 
					more. A container is very different, because almost all of those tasks
 | 
				
			||||||
 | 
					are handled by the infrastructure around the container:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* SSH access will typically be managed by a single server running in
 | 
				
			||||||
 | 
					  the Docker host;
 | 
				
			||||||
 | 
					* ``cron``, when necessary, should run as a user process, dedicated
 | 
				
			||||||
 | 
					  and tailored for the app that needs its scheduling service, rather
 | 
				
			||||||
 | 
					  than as a platform-wide facility;
 | 
				
			||||||
 | 
					* log management will also typically be handed to Docker, or by
 | 
				
			||||||
 | 
					  third-party services like Loggly or Splunk;
 | 
				
			||||||
 | 
					* hardware management is irrelevant, meaning that you never need to
 | 
				
			||||||
 | 
					  run ``udevd`` or equivalent daemons within containers;
 | 
				
			||||||
 | 
					* network management happens outside of the containers, enforcing
 | 
				
			||||||
 | 
					  separation of concerns as much as possible, meaning that a container
 | 
				
			||||||
 | 
					  should never need to perform ``ifconfig``, ``route``, or ip commands
 | 
				
			||||||
 | 
					  (except when a container is specifically engineered to behave like a
 | 
				
			||||||
 | 
					  router or firewall, of course).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This means that in most cases, containers will not need "real" root
 | 
				
			||||||
 | 
					privileges *at all*. And therefore, containers can run with a reduced
 | 
				
			||||||
 | 
					capability set; meaning that "root" within a container has much less
 | 
				
			||||||
 | 
					privileges than the real "root". For instance, it is possible to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* deny all "mount" operations;
 | 
				
			||||||
 | 
					* deny access to raw sockets (to prevent packet spoofing);
 | 
				
			||||||
 | 
					* deny access to some filesystem operations, like creating new device
 | 
				
			||||||
 | 
					  nodes, changing the owner of files, or altering attributes
 | 
				
			||||||
 | 
					  (including the immutable flag);
 | 
				
			||||||
 | 
					* deny module loading;
 | 
				
			||||||
 | 
					* and many others.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This means that even if an intruder manages to escalate to root within
 | 
				
			||||||
 | 
					a container, it will be much harder to do serious damage, or to
 | 
				
			||||||
 | 
					escalate to the host.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This won't affect regular web apps; but malicious users will find that
 | 
				
			||||||
 | 
					the arsenal at their disposal has shrunk considerably! You can see
 | 
				
			||||||
 | 
					`the list of dropped capabilities in the Docker code
 | 
				
			||||||
 | 
					<https://github.com/dotcloud/docker/blob/v0.5.0/lxc_template.go#L97>`_,
 | 
				
			||||||
 | 
					and a full list of available capabilities in `Linux manpages
 | 
				
			||||||
 | 
					<http://man7.org/linux/man-pages/man7/capabilities.7.html>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Of course, you can always enable extra capabilities if you really need
 | 
				
			||||||
 | 
					them (for instance, if you want to use a FUSE-based filesystem), but
 | 
				
			||||||
 | 
					by default, Docker containers will be locked down to ensure maximum
 | 
				
			||||||
 | 
					safety.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Other Kernel Security Features
 | 
				
			||||||
 | 
					------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Capabilities are just one of the many security features provided by
 | 
				
			||||||
 | 
					modern Linux kernels. It is also possible to leverage existing,
 | 
				
			||||||
 | 
					well-known systems like TOMOYO, AppArmor, SELinux, GRSEC, etc. with
 | 
				
			||||||
 | 
					Docker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					While Docker currently only enables capabilities, it doesn't interfere
 | 
				
			||||||
 | 
					with the other systems. This means that there are many different ways
 | 
				
			||||||
 | 
					to harden a Docker host. Here are a few examples.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* You can run a kernel with GRSEC and PAX. This will add many safety
 | 
				
			||||||
 | 
					  checks, both at compile-time and run-time; it will also defeat many
 | 
				
			||||||
 | 
					  exploits, thanks to techniques like address randomization. It
 | 
				
			||||||
 | 
					  doesn’t require Docker-specific configuration, since those security
 | 
				
			||||||
 | 
					  features apply system-wide, independently of containers.
 | 
				
			||||||
 | 
					* If your distribution comes with security model templates for LXC
 | 
				
			||||||
 | 
					  containers, you can use them out of the box. For instance, Ubuntu
 | 
				
			||||||
 | 
					  comes with AppArmor templates for LXC, and those templates provide
 | 
				
			||||||
 | 
					  an extra safety net (even though it overlaps greatly with
 | 
				
			||||||
 | 
					  capabilities).
 | 
				
			||||||
 | 
					* You can define your own policies using your favorite access control
 | 
				
			||||||
 | 
					  mechanism. Since Docker containers are standard LXC containers,
 | 
				
			||||||
 | 
					  there is nothing “magic” or specific to Docker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Just like there are many third-party tools to augment Docker
 | 
				
			||||||
 | 
					containers with e.g. special network topologies or shared filesystems,
 | 
				
			||||||
 | 
					you can expect to see tools to harden existing Docker containers
 | 
				
			||||||
 | 
					without affecting Docker’s core.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Conclusions
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Docker containers are, by default, quite secure; especially if you
 | 
				
			||||||
 | 
					take care of running your processes inside the containers as
 | 
				
			||||||
 | 
					non-privileged users (i.e. non root).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can add an extra layer of safety by enabling Apparmor, SELinux,
 | 
				
			||||||
 | 
					GRSEC, or your favorite hardening solution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Last but not least, if you see interesting security features in other
 | 
				
			||||||
 | 
					containerization systems, you will be able to implement them as well
 | 
				
			||||||
 | 
					with Docker, since everything is provided by the kernel anyway.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For more context and especially for comparisons with VMs and other
 | 
				
			||||||
 | 
					container systems, please also see the `original blog post
 | 
				
			||||||
 | 
					<blogsecurity>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _blogsecurity: http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,13 +34,11 @@ This will find the ``ubuntu`` image by name in the :ref:`Central Index
 | 
				
			||||||
<searching_central_index>` and download it from the top-level Central 
 | 
					<searching_central_index>` and download it from the top-level Central 
 | 
				
			||||||
Repository to a local image cache.
 | 
					Repository to a local image cache.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. NOTE:: When the image has successfully downloaded, you will see a 12 
 | 
					.. NOTE:: When the image has successfully downloaded, you will see a
 | 
				
			||||||
character hash ``539c0211cd76: Download complete`` which is the short 
 | 
					   12 character hash ``539c0211cd76: Download complete`` which is the
 | 
				
			||||||
form of the image ID. These short image IDs are the first 12 characters 
 | 
					   short form of the image ID. These short image IDs are the first 12
 | 
				
			||||||
of the full image ID - which can be found using ``docker inspect`` or 
 | 
					   characters of the full image ID - which can be found using ``docker
 | 
				
			||||||
``docker images -notrunc=true``
 | 
					   inspect`` or ``docker images -notrunc=true``
 | 
				
			||||||
 | 
					 | 
				
			||||||
.. _dockergroup:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Running an interactive shell
 | 
					Running an interactive shell
 | 
				
			||||||
----------------------------
 | 
					----------------------------
 | 
				
			||||||
| 
						 | 
					@ -53,33 +51,38 @@ Running an interactive shell
 | 
				
			||||||
  # use the escape sequence Ctrl-p + Ctrl-q
 | 
					  # use the escape sequence Ctrl-p + Ctrl-q
 | 
				
			||||||
  sudo docker run -i -t ubuntu /bin/bash
 | 
					  sudo docker run -i -t ubuntu /bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _dockergroup:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Why ``sudo``?
 | 
					sudo and the docker Group
 | 
				
			||||||
-------------
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ``docker`` daemon always runs as root, and since ``docker``
 | 
					The ``docker`` daemon always runs as root, and since ``docker``
 | 
				
			||||||
version 0.5.2, ``docker`` binds to a Unix socket instead of a TCP
 | 
					version 0.5.2, ``docker`` binds to a Unix socket instead of a TCP
 | 
				
			||||||
port. By default that Unix socket is owned by the user *root*, and so,
 | 
					port. By default that Unix socket is owned by the user *root*, and so,
 | 
				
			||||||
by default, you can access it with ``sudo``.
 | 
					by default, you can access it with ``sudo``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Starting in version 0.5.3, if you create a Unix group called *docker*
 | 
					Starting in version 0.5.3, if you (or your Docker installer) create a
 | 
				
			||||||
and add users to it, then the ``docker`` daemon will make the
 | 
					Unix group called *docker* and add users to it, then the ``docker``
 | 
				
			||||||
ownership of the Unix socket read/writable by the *docker* group when
 | 
					daemon will make the ownership of the Unix socket read/writable by the
 | 
				
			||||||
the daemon starts. The ``docker`` daemon must always run as root, but
 | 
					*docker* group when the daemon starts. The ``docker`` daemon must
 | 
				
			||||||
if you run the ``docker`` client as a user in the *docker* group then
 | 
					always run as root, but if you run the ``docker`` client as a user in
 | 
				
			||||||
you don't need to add ``sudo`` to all the client commands.
 | 
					the *docker* group then you don't need to add ``sudo`` to all the
 | 
				
			||||||
 | 
					client commands.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Example:**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Add the docker group
 | 
					  # Add the docker group if it doesn't already exist.
 | 
				
			||||||
  sudo groupadd docker
 | 
					  sudo groupadd docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Add the ubuntu user to the docker group
 | 
					  # Add the user "ubuntu" to the docker group.
 | 
				
			||||||
 | 
					  # Change the user name to match your preferred user.
 | 
				
			||||||
  # You may have to logout and log back in again for
 | 
					  # You may have to logout and log back in again for
 | 
				
			||||||
  # this to take effect
 | 
					  # this to take effect.
 | 
				
			||||||
  sudo gpasswd -a ubuntu docker
 | 
					  sudo gpasswd -a ubuntu docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Restart the docker daemon
 | 
					  # Restart the docker daemon.
 | 
				
			||||||
  sudo service docker restart
 | 
					  sudo service docker restart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _bind_docker:
 | 
					.. _bind_docker:
 | 
				
			||||||
| 
						 | 
					@ -87,7 +90,7 @@ you don't need to add ``sudo`` to all the client commands.
 | 
				
			||||||
Bind Docker to another host/port or a Unix socket
 | 
					Bind Docker to another host/port or a Unix socket
 | 
				
			||||||
-------------------------------------------------
 | 
					-------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. DANGER:: Changing the default ``docker`` daemon binding to a TCP
 | 
					.. warning:: Changing the default ``docker`` daemon binding to a TCP
 | 
				
			||||||
   port or Unix *docker* user group will increase your security risks
 | 
					   port or Unix *docker* user group will increase your security risks
 | 
				
			||||||
   by allowing non-root users to potentially gain *root* access on the
 | 
					   by allowing non-root users to potentially gain *root* access on the
 | 
				
			||||||
   host (`e.g. #1369
 | 
					   host (`e.g. #1369
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,8 +318,9 @@ this optional but default, you could use a CMD:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ``VOLUME ["/data"]``
 | 
					    ``VOLUME ["/data"]``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The ``VOLUME`` instruction will add one or more new volumes to any
 | 
					The ``VOLUME`` instruction will create a mount point with the specified name and mark it 
 | 
				
			||||||
container created from the image.
 | 
					as holding externally mounted volumes from native host or other containers. For more information/examples 
 | 
				
			||||||
 | 
					and mounting instructions via docker client, refer to :ref:`volume_def` documentation. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3.10 USER
 | 
					3.10 USER
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,14 +29,32 @@ Here are a few sample scripts for systemd and upstart to integrate with docker.
 | 
				
			||||||
Sample Upstart Script
 | 
					Sample Upstart Script
 | 
				
			||||||
---------------------
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this example we've already created a container to run Redis with an id of
 | 
				
			||||||
 | 
					0a7e070b698b.  To create an upstart script for our container, we create a file
 | 
				
			||||||
 | 
					named ``/etc/init/redis.conf`` and place the following into it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: bash
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   description "Redis container"
 | 
					   description "Redis container"
 | 
				
			||||||
   author "Me"
 | 
					   author "Me"
 | 
				
			||||||
   start on filesystem and started lxc-net and started docker
 | 
					   start on filesystem and started docker
 | 
				
			||||||
   stop on runlevel [!2345]
 | 
					   stop on runlevel [!2345]
 | 
				
			||||||
   respawn
 | 
					   respawn
 | 
				
			||||||
   exec docker start -a 0a7e070b698b
 | 
					   script
 | 
				
			||||||
 | 
					     # Wait for docker to finish starting up first.
 | 
				
			||||||
 | 
					     FILE=/var/run/docker.sock
 | 
				
			||||||
 | 
					     while [ ! -e $FILE ] ; do
 | 
				
			||||||
 | 
					       inotifywait -t 2 -e create $(dirname $FILE)
 | 
				
			||||||
 | 
					     done
 | 
				
			||||||
 | 
					     /usr/bin/docker start -a 0a7e070b698b
 | 
				
			||||||
 | 
					   end script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Next, we have to configure docker so that it's run with the option ``-r=false``.
 | 
				
			||||||
 | 
					Run the following command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   $ sudo sh -c "echo 'DOCKER_OPTS=\"-r=false\"' > /etc/default/docker"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Sample systemd Script
 | 
					Sample systemd Script
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,44 +30,60 @@ Each container can have zero or more data volumes.
 | 
				
			||||||
Getting Started
 | 
					Getting Started
 | 
				
			||||||
...............
 | 
					...............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Using data volumes is as simple as adding a new flag: ``-v``. The
 | 
				
			||||||
 | 
					parameter ``-v`` can be used more than once in order to create more
 | 
				
			||||||
Using data volumes is as simple as adding a new flag: ``-v``. The parameter ``-v`` can be used more than once in order to create more volumes within the new container. The example below shows the instruction to create a container with two new volumes::
 | 
					volumes within the new container. The example below shows the
 | 
				
			||||||
 | 
					instruction to create a container with two new volumes::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  docker run -v /var/volume1 -v /var/volume2 shykes/couchdb
 | 
					  docker run -v /var/volume1 -v /var/volume2 shykes/couchdb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For a Dockerfile, the VOLUME instruction will add one or more new volumes to any container created from the image::
 | 
					For a Dockerfile, the VOLUME instruction will add one or more new
 | 
				
			||||||
 | 
					volumes to any container created from the image::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  VOLUME ["/var/volume1", "/var/volume2"]
 | 
					  VOLUME ["/var/volume1", "/var/volume2"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Create a new container using existing volumes from an existing container:
 | 
					Mount Volumes from an Existing Container:
 | 
				
			||||||
---------------------------------------------------------------------------
 | 
					-----------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The command below creates a new container which is runnning as daemon
 | 
				
			||||||
The command below creates a new container which is runnning as daemon ``-d`` and with one volume ``/var/lib/couchdb``::
 | 
					``-d`` and with one volume ``/var/lib/couchdb``::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
 | 
					  COUCH1=$(sudo docker run -d -v /var/lib/couchdb shykes/couchdb:2013-05-03)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
From the container id of that previous container ``$COUCH1`` it's possible to create new container sharing the same volume using the parameter ``-volumes-from container_id``::
 | 
					From the container id of that previous container ``$COUCH1`` it's
 | 
				
			||||||
 | 
					possible to create new container sharing the same volume using the
 | 
				
			||||||
 | 
					parameter ``-volumes-from container_id``::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
 | 
					  COUCH2=$(sudo docker run -d -volumes-from $COUCH1 shykes/couchdb:2013-05-03)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Now, the second container has the all the information from the first volume.
 | 
					Now, the second container has the all the information from the first volume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Create a new container which mounts a host directory into it:
 | 
					Mount a Host Directory as a Container Volume:
 | 
				
			||||||
-------------------------------------------------------------
 | 
					---------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro].
 | 
					  -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro].
 | 
				
			||||||
  If "host-dir" is missing, then docker creates a new volume.
 | 
					  If "host-dir" is missing, then docker creates a new volume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  This is not available for a Dockerfile due the portability and sharing purpose of it. The [host-dir] volumes is something    100% host dependent and will break on any other machine.
 | 
					This is not available for a Dockerfile due the portability and sharing
 | 
				
			||||||
 | 
					purpose of it. The [host-dir] volumes is something 100% host dependent
 | 
				
			||||||
 | 
					and will break on any other machine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For example::
 | 
					For example::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sudo docker run -v /var/logs:/var/host_logs:ro shykes/couchdb:2013-05-03
 | 
					  sudo docker run -v /var/logs:/var/host_logs:ro shykes/couchdb:2013-05-03
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The command above mounts the host directory ``/var/logs`` into the container with read only permissions as ``/var/host_logs``.
 | 
					The command above mounts the host directory ``/var/logs`` into the
 | 
				
			||||||
 | 
					container with read only permissions as ``/var/host_logs``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. versionadded:: v0.5.0
 | 
					.. versionadded:: v0.5.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Known Issues
 | 
				
			||||||
 | 
					............
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* :issue:`2702`: "lxc-start: Permission denied - failed to mount"
 | 
				
			||||||
 | 
					  could indicate a permissions problem with AppArmor. Please see the
 | 
				
			||||||
 | 
					  issue for a workaround.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,6 +177,15 @@ you can push and pull it like any other repository, but it will
 | 
				
			||||||
there will be no user name checking performed. Your registry will
 | 
					there will be no user name checking performed. Your registry will
 | 
				
			||||||
function completely independently from the Central Index.
 | 
					function completely independently from the Central Index.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. raw:: html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   <iframe width="640" height="360"
 | 
				
			||||||
 | 
					   src="//www.youtube.com/embed/CAewZCBT4PI?rel=0" frameborder="0"
 | 
				
			||||||
 | 
					   allowfullscreen></iframe>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. seealso:: `Docker Blog: How to use your own registry 
 | 
				
			||||||
 | 
					   <http://blog.docker.io/2013/07/how-to-use-your-own-registry/>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Authentication file
 | 
					Authentication file
 | 
				
			||||||
-------------------
 | 
					-------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,7 +214,7 @@ func (job *Job) GetenvList(key string) []string {
 | 
				
			||||||
	return l
 | 
						return l
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (job *Job) SetenvList(key string, value []string) error {
 | 
					func (job *Job) SetenvJson(key string, value interface{}) error {
 | 
				
			||||||
	sval, err := json.Marshal(value)
 | 
						sval, err := json.Marshal(value)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -223,6 +223,10 @@ func (job *Job) SetenvList(key string, value []string) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (job *Job) SetenvList(key string, value []string) error {
 | 
				
			||||||
 | 
						return job.SetenvJson(key, value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (job *Job) Setenv(key, value string) {
 | 
					func (job *Job) Setenv(key, value string) {
 | 
				
			||||||
	job.env = append(job.env, key+"="+value)
 | 
						job.env = append(job.env, key+"="+value)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								graph.go
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								graph.go
									
										
									
									
									
								
							| 
						 | 
					@ -231,12 +231,11 @@ func setupInitLayer(initLayer string) error {
 | 
				
			||||||
					if err := os.MkdirAll(path.Join(initLayer, path.Dir(pth)), 0755); err != nil {
 | 
										if err := os.MkdirAll(path.Join(initLayer, path.Dir(pth)), 0755); err != nil {
 | 
				
			||||||
						return err
 | 
											return err
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755)
 | 
				
			||||||
					if f, err := os.OpenFile(path.Join(initLayer, pth), os.O_CREATE, 0755); err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						return err
 | 
											return err
 | 
				
			||||||
					} else {
 | 
					 | 
				
			||||||
						f.Close()
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										f.Close()
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@ import (
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -122,41 +121,6 @@ func TestRegister(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMount(t *testing.T) {
 | 
					 | 
				
			||||||
	graph := tempGraph(t)
 | 
					 | 
				
			||||||
	defer os.RemoveAll(graph.Root)
 | 
					 | 
				
			||||||
	archive, err := fakeTar()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	image, err := graph.Create(archive, nil, "Testing", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	tmp, err := ioutil.TempDir("", "docker-test-graph-mount-")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer os.RemoveAll(tmp)
 | 
					 | 
				
			||||||
	rootfs := path.Join(tmp, "rootfs")
 | 
					 | 
				
			||||||
	if err := os.MkdirAll(rootfs, 0700); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rw := path.Join(tmp, "rw")
 | 
					 | 
				
			||||||
	if err := os.MkdirAll(rw, 0700); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if _, err := graph.driver.Get(image.ID); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// FIXME: test for mount contents
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if err := graph.driver.Cleanup(); err != nil {
 | 
					 | 
				
			||||||
			t.Error(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Test that an image can be deleted by its shorthand prefix
 | 
					// Test that an image can be deleted by its shorthand prefix
 | 
				
			||||||
func TestDeletePrefix(t *testing.T) {
 | 
					func TestDeletePrefix(t *testing.T) {
 | 
				
			||||||
	graph := tempGraph(t)
 | 
						graph := tempGraph(t)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								http_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								http_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGetBoolParam(t *testing.T) {
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("true"); err != nil || !ret {
 | 
				
			||||||
 | 
							t.Fatalf("true -> true, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("True"); err != nil || !ret {
 | 
				
			||||||
 | 
							t.Fatalf("True -> true, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("1"); err != nil || !ret {
 | 
				
			||||||
 | 
							t.Fatalf("1 -> true, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam(""); err != nil || ret {
 | 
				
			||||||
 | 
							t.Fatalf("\"\" -> false, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("false"); err != nil || ret {
 | 
				
			||||||
 | 
							t.Fatalf("false -> false, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("0"); err != nil || ret {
 | 
				
			||||||
 | 
							t.Fatalf("0 -> false, nil | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ret, err := getBoolParam("faux"); err == nil || ret {
 | 
				
			||||||
 | 
							t.Fatalf("faux -> false, err | got %t %s", ret, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TesthttpError(t *testing.T) {
 | 
				
			||||||
 | 
						r := httptest.NewRecorder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpError(r, fmt.Errorf("No such method"))
 | 
				
			||||||
 | 
						if r.Code != http.StatusNotFound {
 | 
				
			||||||
 | 
							t.Fatalf("Expected %d, got %d", http.StatusNotFound, r.Code)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpError(r, fmt.Errorf("This accound hasn't been activated"))
 | 
				
			||||||
 | 
						if r.Code != http.StatusForbidden {
 | 
				
			||||||
 | 
							t.Fatalf("Expected %d, got %d", http.StatusForbidden, r.Code)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						httpError(r, fmt.Errorf("Some error"))
 | 
				
			||||||
 | 
						if r.Code != http.StatusInternalServerError {
 | 
				
			||||||
 | 
							t.Fatalf("Expected %d, got %d", http.StatusInternalServerError, r.Code)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								image.go
									
										
									
									
									
								
							
							
						
						
									
										30
									
								
								image.go
									
										
									
									
									
								
							| 
						 | 
					@ -52,11 +52,11 @@ func LoadImage(root string) (*Image, error) {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if size, err := strconv.Atoi(string(buf)); err != nil {
 | 
							size, err := strconv.Atoi(string(buf))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			img.Size = int64(size)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							img.Size = int64(size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return img, nil
 | 
						return img, nil
 | 
				
			||||||
| 
						 | 
					@ -88,14 +88,14 @@ func StoreImage(img *Image, jsonData []byte, layerData archive.Archive, root, ro
 | 
				
			||||||
	// If raw json is provided, then use it
 | 
						// If raw json is provided, then use it
 | 
				
			||||||
	if jsonData != nil {
 | 
						if jsonData != nil {
 | 
				
			||||||
		return ioutil.WriteFile(jsonPath(root), jsonData, 0600)
 | 
							return ioutil.WriteFile(jsonPath(root), jsonData, 0600)
 | 
				
			||||||
	} else { // Otherwise, unmarshal the image
 | 
						}
 | 
				
			||||||
		jsonData, err := json.Marshal(img)
 | 
						// Otherwise, unmarshal the image
 | 
				
			||||||
		if err != nil {
 | 
						jsonData, err := json.Marshal(img)
 | 
				
			||||||
			return err
 | 
						if err != nil {
 | 
				
			||||||
		}
 | 
							return err
 | 
				
			||||||
		if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
 | 
						}
 | 
				
			||||||
			return err
 | 
						if err := ioutil.WriteFile(jsonPath(root), jsonData, 0600); err != nil {
 | 
				
			||||||
		}
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Compute and save the size of the rootfs
 | 
						// Compute and save the size of the rootfs
 | 
				
			||||||
	size, err := utils.TreeSize(rootfs)
 | 
						size, err := utils.TreeSize(rootfs)
 | 
				
			||||||
| 
						 | 
					@ -123,11 +123,11 @@ func jsonPath(root string) string {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TarLayer returns a tar archive of the image's filesystem layer.
 | 
					// TarLayer returns a tar archive of the image's filesystem layer.
 | 
				
			||||||
func (image *Image) TarLayer(compression archive.Compression) (archive.Archive, error) {
 | 
					func (img *Image) TarLayer(compression archive.Compression) (archive.Archive, error) {
 | 
				
			||||||
	if image.graph == nil {
 | 
						if img.graph == nil {
 | 
				
			||||||
		return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", image.ID)
 | 
							return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	layerPath, err := image.graph.driver.Get(image.ID)
 | 
						layerPath, err := img.graph.driver.Get(img.ID)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										61
									
								
								integration/auth_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								integration/auth_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/auth"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: these tests have an external dependency on a staging index hosted
 | 
				
			||||||
 | 
					// on the docker.io infrastructure. That dependency should be removed.
 | 
				
			||||||
 | 
					// - Unit tests should have no side-effect dependencies.
 | 
				
			||||||
 | 
					// - Integration tests should have side-effects limited to the host environment being tested.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLogin(t *testing.T) {
 | 
				
			||||||
 | 
						os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
 | 
				
			||||||
 | 
						defer os.Setenv("DOCKER_INDEX_URL", "")
 | 
				
			||||||
 | 
						authConfig := &auth.AuthConfig{Username: "unittester", Password: "surlautrerivejetattendrai", Email: "noise+unittester@dotcloud.com"}
 | 
				
			||||||
 | 
						status, err := auth.Login(authConfig, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if status != "Login Succeeded" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected status \"Login Succeeded\", found \"%s\" instead", status)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCreateAccount(t *testing.T) {
 | 
				
			||||||
 | 
						os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
 | 
				
			||||||
 | 
						defer os.Setenv("DOCKER_INDEX_URL", "")
 | 
				
			||||||
 | 
						tokenBuffer := make([]byte, 16)
 | 
				
			||||||
 | 
						_, err := rand.Read(tokenBuffer)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						token := hex.EncodeToString(tokenBuffer)[:12]
 | 
				
			||||||
 | 
						username := "ut" + token
 | 
				
			||||||
 | 
						authConfig := &auth.AuthConfig{Username: username, Password: "test42", Email: "docker-ut+" + token + "@example.com"}
 | 
				
			||||||
 | 
						status, err := auth.Login(authConfig, nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						expectedStatus := "Account created. Please use the confirmation link we sent" +
 | 
				
			||||||
 | 
							" to your e-mail to activate it."
 | 
				
			||||||
 | 
						if status != expectedStatus {
 | 
				
			||||||
 | 
							t.Fatalf("Expected status: \"%s\", found \"%s\" instead.", expectedStatus, status)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status, err = auth.Login(authConfig, nil)
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Expected error but found nil instead")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						expectedError := "Login: Account is not Active"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !strings.Contains(err.Error(), expectedError) {
 | 
				
			||||||
 | 
							t.Fatalf("Expected message \"%s\" but found \"%s\" instead", expectedError, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,9 @@ package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
	"github.com/dotcloud/docker/archive"
 | 
						"github.com/dotcloud/docker/archive"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/engine"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
| 
						 | 
					@ -14,7 +16,7 @@ import (
 | 
				
			||||||
// mkTestContext generates a build context from the contents of the provided dockerfile.
 | 
					// mkTestContext generates a build context from the contents of the provided dockerfile.
 | 
				
			||||||
// This context is suitable for use as an argument to BuildFile.Build()
 | 
					// This context is suitable for use as an argument to BuildFile.Build()
 | 
				
			||||||
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) archive.Archive {
 | 
					func mkTestContext(dockerfile string, files [][2]string, t *testing.T) archive.Archive {
 | 
				
			||||||
	context, err := mkBuildContext(dockerfile, files)
 | 
						context, err := docker.MkBuildContext(dockerfile, files)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -228,17 +230,15 @@ func TestBuild(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache bool) *Image {
 | 
					func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, useCache bool) *docker.Image {
 | 
				
			||||||
	if srv == nil {
 | 
						if eng == nil {
 | 
				
			||||||
		runtime := mkRuntime(t)
 | 
							eng = NewTestEngine(t)
 | 
				
			||||||
 | 
							runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
							// FIXME: we might not need runtime, why not simply nuke
 | 
				
			||||||
 | 
							// the engine?
 | 
				
			||||||
		defer nuke(runtime)
 | 
							defer nuke(runtime)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		srv = &Server{
 | 
					 | 
				
			||||||
			runtime:     runtime,
 | 
					 | 
				
			||||||
			pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
			pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	httpServer, err := mkTestingFileServer(context.remoteFiles)
 | 
						httpServer, err := mkTestingFileServer(context.remoteFiles)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -252,10 +252,17 @@ func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	port := httpServer.URL[idx+1:]
 | 
						port := httpServer.URL[idx+1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip := srv.runtime.networkManager.bridgeNetwork.IP
 | 
						iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
 | 
				
			||||||
 | 
						if iIP == nil {
 | 
				
			||||||
 | 
							t.Fatal("Legacy bridgeIP field not set in engine")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ip, ok := iIP.(net.IP)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							panic("Legacy bridgeIP field in engine does not cast to net.IP")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
						dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buildfile := NewBuildFile(srv, ioutil.Discard, false, useCache, false)
 | 
						buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, useCache, false)
 | 
				
			||||||
	id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
						id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					@ -368,20 +375,14 @@ func TestBuildEntrypoint(t *testing.T) {
 | 
				
			||||||
// testing #1405 - config.Cmd does not get cleaned up if
 | 
					// testing #1405 - config.Cmd does not get cleaned up if
 | 
				
			||||||
// utilizing cache
 | 
					// utilizing cache
 | 
				
			||||||
func TestBuildEntrypointRunCleanup(t *testing.T) {
 | 
					func TestBuildEntrypointRunCleanup(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img := buildImage(testContextTemplate{`
 | 
						img := buildImage(testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
        run echo "hello"
 | 
					        run echo "hello"
 | 
				
			||||||
        `,
 | 
					        `,
 | 
				
			||||||
		nil, nil}, t, srv, true)
 | 
							nil, nil}, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img = buildImage(testContextTemplate{`
 | 
						img = buildImage(testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
| 
						 | 
					@ -389,7 +390,7 @@ func TestBuildEntrypointRunCleanup(t *testing.T) {
 | 
				
			||||||
        add foo /foo
 | 
					        add foo /foo
 | 
				
			||||||
        entrypoint ["/bin/echo"]
 | 
					        entrypoint ["/bin/echo"]
 | 
				
			||||||
        `,
 | 
					        `,
 | 
				
			||||||
		[][2]string{{"foo", "HEYO"}}, nil}, t, srv, true)
 | 
							[][2]string{{"foo", "HEYO"}}, nil}, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(img.Config.Cmd) != 0 {
 | 
						if len(img.Config.Cmd) != 0 {
 | 
				
			||||||
		t.Fail()
 | 
							t.Fail()
 | 
				
			||||||
| 
						 | 
					@ -397,14 +398,8 @@ func TestBuildEntrypointRunCleanup(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildImageWithCache(t *testing.T) {
 | 
					func TestBuildImageWithCache(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template := testContextTemplate{`
 | 
						template := testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
| 
						 | 
					@ -412,11 +407,11 @@ func TestBuildImageWithCache(t *testing.T) {
 | 
				
			||||||
        `,
 | 
					        `,
 | 
				
			||||||
		nil, nil}
 | 
							nil, nil}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img := buildImage(template, t, srv, true)
 | 
						img := buildImage(template, t, eng, true)
 | 
				
			||||||
	imageId := img.ID
 | 
						imageId := img.ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img = nil
 | 
						img = nil
 | 
				
			||||||
	img = buildImage(template, t, srv, true)
 | 
						img = buildImage(template, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if imageId != img.ID {
 | 
						if imageId != img.ID {
 | 
				
			||||||
		t.Logf("Image ids should match: %s != %s", imageId, img.ID)
 | 
							t.Logf("Image ids should match: %s != %s", imageId, img.ID)
 | 
				
			||||||
| 
						 | 
					@ -425,14 +420,8 @@ func TestBuildImageWithCache(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildImageWithoutCache(t *testing.T) {
 | 
					func TestBuildImageWithoutCache(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template := testContextTemplate{`
 | 
						template := testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
| 
						 | 
					@ -440,11 +429,11 @@ func TestBuildImageWithoutCache(t *testing.T) {
 | 
				
			||||||
        `,
 | 
					        `,
 | 
				
			||||||
		nil, nil}
 | 
							nil, nil}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img := buildImage(template, t, srv, true)
 | 
						img := buildImage(template, t, eng, true)
 | 
				
			||||||
	imageId := img.ID
 | 
						imageId := img.ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img = nil
 | 
						img = nil
 | 
				
			||||||
	img = buildImage(template, t, srv, false)
 | 
						img = buildImage(template, t, eng, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if imageId == img.ID {
 | 
						if imageId == img.ID {
 | 
				
			||||||
		t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
 | 
							t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
 | 
				
			||||||
| 
						 | 
					@ -453,14 +442,9 @@ func TestBuildImageWithoutCache(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestForbiddenContextPath(t *testing.T) {
 | 
					func TestForbiddenContextPath(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	context := testContextTemplate{`
 | 
						context := testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
| 
						 | 
					@ -481,10 +465,17 @@ func TestForbiddenContextPath(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	port := httpServer.URL[idx+1:]
 | 
						port := httpServer.URL[idx+1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip := srv.runtime.networkManager.bridgeNetwork.IP
 | 
						iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
 | 
				
			||||||
 | 
						if iIP == nil {
 | 
				
			||||||
 | 
							t.Fatal("Legacy bridgeIP field not set in engine")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ip, ok := iIP.(net.IP)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							panic("Legacy bridgeIP field in engine does not cast to net.IP")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
						dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buildfile := NewBuildFile(srv, ioutil.Discard, false, true, false)
 | 
						buildfile := docker.NewBuildFile(srv, ioutil.Discard, false, true, false)
 | 
				
			||||||
	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
						_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
| 
						 | 
					@ -499,14 +490,8 @@ func TestForbiddenContextPath(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildADDFileNotFound(t *testing.T) {
 | 
					func TestBuildADDFileNotFound(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	context := testContextTemplate{`
 | 
						context := testContextTemplate{`
 | 
				
			||||||
        from {IMAGE}
 | 
					        from {IMAGE}
 | 
				
			||||||
| 
						 | 
					@ -526,10 +511,17 @@ func TestBuildADDFileNotFound(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	port := httpServer.URL[idx+1:]
 | 
						port := httpServer.URL[idx+1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ip := srv.runtime.networkManager.bridgeNetwork.IP
 | 
						iIP := eng.Hack_GetGlobalVar("httpapi.bridgeIP")
 | 
				
			||||||
 | 
						if iIP == nil {
 | 
				
			||||||
 | 
							t.Fatal("Legacy bridgeIP field not set in engine")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ip, ok := iIP.(net.IP)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							panic("Legacy bridgeIP field in engine does not cast to net.IP")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
						dockerfile := constructDockerfile(context.dockerfile, ip, port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buildfile := NewBuildFile(srv, ioutil.Discard, false, true, false)
 | 
						buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, false, true, false)
 | 
				
			||||||
	_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
						_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
| 
						 | 
					@ -544,26 +536,20 @@ func TestBuildADDFileNotFound(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBuildInheritance(t *testing.T) {
 | 
					func TestBuildInheritance(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img := buildImage(testContextTemplate{`
 | 
						img := buildImage(testContextTemplate{`
 | 
				
			||||||
            from {IMAGE}
 | 
					            from {IMAGE}
 | 
				
			||||||
            expose 4243
 | 
					            expose 4243
 | 
				
			||||||
            `,
 | 
					            `,
 | 
				
			||||||
		nil, nil}, t, srv, true)
 | 
							nil, nil}, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	img2 := buildImage(testContextTemplate{fmt.Sprintf(`
 | 
						img2 := buildImage(testContextTemplate{fmt.Sprintf(`
 | 
				
			||||||
            from %s
 | 
					            from %s
 | 
				
			||||||
            entrypoint ["/bin/echo"]
 | 
					            entrypoint ["/bin/echo"]
 | 
				
			||||||
            `, img.ID),
 | 
					            `, img.ID),
 | 
				
			||||||
		nil, nil}, t, srv, true)
 | 
							nil, nil}, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// from child
 | 
						// from child
 | 
				
			||||||
	if img2.Config.Entrypoint[0] != "/bin/echo" {
 | 
						if img2.Config.Entrypoint[0] != "/bin/echo" {
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,8 @@ package docker
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/engine"
 | 
				
			||||||
	"github.com/dotcloud/docker/utils"
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
| 
						 | 
					@ -66,8 +68,8 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error
 | 
				
			||||||
func TestRunHostname(t *testing.T) {
 | 
					func TestRunHostname(t *testing.T) {
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -111,8 +113,8 @@ func TestRunHostname(t *testing.T) {
 | 
				
			||||||
func TestRunWorkdir(t *testing.T) {
 | 
					func TestRunWorkdir(t *testing.T) {
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -156,8 +158,8 @@ func TestRunWorkdir(t *testing.T) {
 | 
				
			||||||
func TestRunWorkdirExists(t *testing.T) {
 | 
					func TestRunWorkdirExists(t *testing.T) {
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -201,8 +203,8 @@ func TestRunExit(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c1 := make(chan struct{})
 | 
						c1 := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -254,8 +256,8 @@ func TestRunDisconnect(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c1 := make(chan struct{})
 | 
						c1 := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -299,8 +301,8 @@ func TestRunDisconnectTty(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c1 := make(chan struct{})
 | 
						c1 := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -356,8 +358,8 @@ func TestRunAttachStdin(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch := make(chan struct{})
 | 
						ch := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -420,8 +422,8 @@ func TestRunDetach(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch := make(chan struct{})
 | 
						ch := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -466,8 +468,8 @@ func TestAttachDetach(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch := make(chan struct{})
 | 
						ch := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -477,7 +479,7 @@ func TestAttachDetach(t *testing.T) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var container *Container
 | 
						var container *docker.Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
 | 
						setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
 | 
				
			||||||
		buf := make([]byte, 1024)
 | 
							buf := make([]byte, 1024)
 | 
				
			||||||
| 
						 | 
					@ -498,7 +500,7 @@ func TestAttachDetach(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stdin, stdinPipe = io.Pipe()
 | 
						stdin, stdinPipe = io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe = io.Pipe()
 | 
						stdout, stdoutPipe = io.Pipe()
 | 
				
			||||||
	cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli = docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch = make(chan struct{})
 | 
						ch = make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -546,8 +548,8 @@ func TestAttachDetachTruncatedID(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go stdout.Read(make([]byte, 1024))
 | 
						go stdout.Read(make([]byte, 1024))
 | 
				
			||||||
	setTimeout(t, "Starting container timed out", 2*time.Second, func() {
 | 
						setTimeout(t, "Starting container timed out", 2*time.Second, func() {
 | 
				
			||||||
| 
						 | 
					@ -560,7 +562,7 @@ func TestAttachDetachTruncatedID(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stdin, stdinPipe = io.Pipe()
 | 
						stdin, stdinPipe = io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe = io.Pipe()
 | 
						stdout, stdoutPipe = io.Pipe()
 | 
				
			||||||
	cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli = docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ch := make(chan struct{})
 | 
						ch := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -608,8 +610,8 @@ func TestAttachDisconnect(t *testing.T) {
 | 
				
			||||||
	stdin, stdinPipe := io.Pipe()
 | 
						stdin, stdinPipe := io.Pipe()
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		// Start a process in daemon mode
 | 
							// Start a process in daemon mode
 | 
				
			||||||
| 
						 | 
					@ -677,8 +679,8 @@ func TestAttachDisconnect(t *testing.T) {
 | 
				
			||||||
func TestRunAutoRemove(t *testing.T) {
 | 
					func TestRunAutoRemove(t *testing.T) {
 | 
				
			||||||
	t.Skip("Fixme. Skipping test for now, race condition")
 | 
						t.Skip("Fixme. Skipping test for now, race condition")
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -712,8 +714,8 @@ func TestRunAutoRemove(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCmdLogs(t *testing.T) {
 | 
					func TestCmdLogs(t *testing.T) {
 | 
				
			||||||
	cli := NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := cli.CmdRun(unitTestImageID, "sh", "-c", "ls -l"); err != nil {
 | 
						if err := cli.CmdRun(unitTestImageID, "sh", "-c", "ls -l"); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
| 
						 | 
					@ -730,8 +732,8 @@ func TestCmdLogs(t *testing.T) {
 | 
				
			||||||
// Expected behaviour: using / as a bind mount source should throw an error
 | 
					// Expected behaviour: using / as a bind mount source should throw an error
 | 
				
			||||||
func TestRunErrorBindMountRootSource(t *testing.T) {
 | 
					func TestRunErrorBindMountRootSource(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -749,8 +751,8 @@ func TestRunErrorBindMountRootSource(t *testing.T) {
 | 
				
			||||||
// Expected behaviour: error out when attempting to bind mount non-existing source paths
 | 
					// Expected behaviour: error out when attempting to bind mount non-existing source paths
 | 
				
			||||||
func TestRunErrorBindNonExistingSource(t *testing.T) {
 | 
					func TestRunErrorBindNonExistingSource(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -768,11 +770,10 @@ func TestRunErrorBindNonExistingSource(t *testing.T) {
 | 
				
			||||||
func TestImagesViz(t *testing.T) {
 | 
					func TestImagesViz(t *testing.T) {
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srv := &Server{runtime: globalRuntime}
 | 
						image := buildTestImages(t, globalEngine)
 | 
				
			||||||
	image := buildTestImages(t, srv)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -819,11 +820,10 @@ func TestImagesViz(t *testing.T) {
 | 
				
			||||||
func TestImagesTree(t *testing.T) {
 | 
					func TestImagesTree(t *testing.T) {
 | 
				
			||||||
	stdout, stdoutPipe := io.Pipe()
 | 
						stdout, stdoutPipe := io.Pipe()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srv := &Server{runtime: globalRuntime}
 | 
						image := buildTestImages(t, globalEngine)
 | 
				
			||||||
	image := buildTestImages(t, srv)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -866,7 +866,7 @@ func TestImagesTree(t *testing.T) {
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func buildTestImages(t *testing.T, srv *Server) *Image {
 | 
					func buildTestImages(t *testing.T, eng *engine.Engine) *docker.Image {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var testBuilder = testContextTemplate{
 | 
						var testBuilder = testContextTemplate{
 | 
				
			||||||
		`
 | 
							`
 | 
				
			||||||
| 
						 | 
					@ -879,9 +879,9 @@ run    [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
 | 
				
			||||||
		nil,
 | 
							nil,
 | 
				
			||||||
		nil,
 | 
							nil,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	image := buildImage(testBuilder, t, srv, true)
 | 
						image := buildImage(testBuilder, t, eng, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := srv.ContainerTag(image.ID, "test", "latest", false)
 | 
						err := mkServerFromEngine(eng, t).ContainerTag(image.ID, "test", "latest", false)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -901,8 +901,8 @@ func TestRunCidFile(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tmpCidFile := path.Join(tmpDir, "cid")
 | 
						tmpCidFile := path.Join(tmpDir, "cid")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
						cli := docker.NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
 | 
				
			||||||
	defer cleanup(globalRuntime)
 | 
						defer cleanup(globalEngine, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c := make(chan struct{})
 | 
						c := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,10 @@ package docker
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
	"github.com/dotcloud/docker/utils"
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"math/rand"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ func TestIDFormat(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container1, _, err := runtime.Create(
 | 
						container1, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image: GetTestImage(runtime).ID,
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
 | 
								Cmd:   []string{"/bin/sh", "-c", "echo hello world"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ func TestIDFormat(t *testing.T) {
 | 
				
			||||||
func TestMultipleAttachRestart(t *testing.T) {
 | 
					func TestMultipleAttachRestart(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _ := mkContainer(
 | 
						container, _, _ := mkContainer(
 | 
				
			||||||
		runtime,
 | 
							runtime,
 | 
				
			||||||
		[]string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`;  echo hello; done"},
 | 
							[]string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`;  echo hello; done"},
 | 
				
			||||||
		t,
 | 
							t,
 | 
				
			||||||
| 
						 | 
					@ -134,10 +134,11 @@ func TestMultipleAttachRestart(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDiff(t *testing.T) {
 | 
					func TestDiff(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	// Create a container and remove a file
 | 
						// Create a container and remove a file
 | 
				
			||||||
	container1, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
 | 
						container1, _, _ := mkContainer(runtime, []string{"_", "/bin/rm", "/etc/passwd"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container1)
 | 
						defer runtime.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The changelog should be empty and not fail before run. See #1705
 | 
						// The changelog should be empty and not fail before run. See #1705
 | 
				
			||||||
| 
						 | 
					@ -169,17 +170,13 @@ func TestDiff(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Commit the container
 | 
						// Commit the container
 | 
				
			||||||
	rwTar, err := container1.ExportRw()
 | 
						img, err := runtime.Commit(container1, "", "", "unit test commited image - diff", "", nil)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image - diff", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create a new container from the commited image
 | 
						// Create a new container from the commited image
 | 
				
			||||||
	container2, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
 | 
						container2, _, _ := mkContainer(runtime, []string{img.ID, "cat", "/etc/passwd"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container2)
 | 
						defer runtime.Destroy(container2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := container2.Run(); err != nil {
 | 
						if err := container2.Run(); err != nil {
 | 
				
			||||||
| 
						 | 
					@ -198,7 +195,7 @@ func TestDiff(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create a new container
 | 
						// Create a new container
 | 
				
			||||||
	container3, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
 | 
						container3, _, _ := mkContainer(runtime, []string{"_", "rm", "/bin/httpd"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container3)
 | 
						defer runtime.Destroy(container3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := container3.Run(); err != nil {
 | 
						if err := container3.Run(); err != nil {
 | 
				
			||||||
| 
						 | 
					@ -224,7 +221,7 @@ func TestDiff(t *testing.T) {
 | 
				
			||||||
func TestCommitAutoRun(t *testing.T) {
 | 
					func TestCommitAutoRun(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container1, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
 | 
						container1, _, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container1)
 | 
						defer runtime.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container1.State.Running {
 | 
						if container1.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -237,17 +234,13 @@ func TestCommitAutoRun(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Container shouldn't be running")
 | 
							t.Errorf("Container shouldn't be running")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rwTar, err := container1.ExportRw()
 | 
						img, err := runtime.Commit(container1, "", "", "unit test commited image", "", &docker.Config{Cmd: []string{"cat", "/world"}})
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", &Config{Cmd: []string{"cat", "/world"}})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
 | 
						// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
 | 
				
			||||||
	container2, _ := mkContainer(runtime, []string{img.ID}, t)
 | 
						container2, _, _ := mkContainer(runtime, []string{img.ID}, t)
 | 
				
			||||||
	defer runtime.Destroy(container2)
 | 
						defer runtime.Destroy(container2)
 | 
				
			||||||
	stdout, err := container2.StdoutPipe()
 | 
						stdout, err := container2.StdoutPipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -284,7 +277,7 @@ func TestCommitRun(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container1, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
 | 
						container1, _, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container1)
 | 
						defer runtime.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container1.State.Running {
 | 
						if container1.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -297,17 +290,13 @@ func TestCommitRun(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Container shouldn't be running")
 | 
							t.Errorf("Container shouldn't be running")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rwTar, err := container1.ExportRw()
 | 
						img, err := runtime.Commit(container1, "", "", "unit test commited image", "", nil)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	img, err := runtime.graph.Create(rwTar, container1, "unit test commited image", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
 | 
						// FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world
 | 
				
			||||||
	container2, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
 | 
						container2, _, _ := mkContainer(runtime, []string{img.ID, "cat", "/world"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container2)
 | 
						defer runtime.Destroy(container2)
 | 
				
			||||||
	stdout, err := container2.StdoutPipe()
 | 
						stdout, err := container2.StdoutPipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -343,7 +332,7 @@ func TestCommitRun(t *testing.T) {
 | 
				
			||||||
func TestStart(t *testing.T) {
 | 
					func TestStart(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
 | 
						container, _, _ := mkContainer(runtime, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container)
 | 
						defer runtime.Destroy(container)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cStdin, err := container.StdinPipe()
 | 
						cStdin, err := container.StdinPipe()
 | 
				
			||||||
| 
						 | 
					@ -373,7 +362,7 @@ func TestStart(t *testing.T) {
 | 
				
			||||||
func TestRun(t *testing.T) {
 | 
					func TestRun(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
						container, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container)
 | 
						defer runtime.Destroy(container)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.State.Running {
 | 
						if container.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -391,7 +380,7 @@ func TestOutput(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image: GetTestImage(runtime).ID,
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:   []string{"echo", "-n", "foobar"},
 | 
								Cmd:   []string{"echo", "-n", "foobar"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -414,7 +403,7 @@ func TestContainerNetwork(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image: GetTestImage(runtime).ID,
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:   []string{"ping", "-c", "1", "127.0.0.1"},
 | 
								Cmd:   []string{"ping", "-c", "1", "127.0.0.1"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -436,7 +425,7 @@ func TestKillDifferentUser(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image:     GetTestImage(runtime).ID,
 | 
							Image:     GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:       []string{"cat"},
 | 
							Cmd:       []string{"cat"},
 | 
				
			||||||
		OpenStdin: true,
 | 
							OpenStdin: true,
 | 
				
			||||||
| 
						 | 
					@ -448,7 +437,9 @@ func TestKillDifferentUser(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer runtime.Destroy(container)
 | 
						defer runtime.Destroy(container)
 | 
				
			||||||
	defer container.stdin.Close()
 | 
						// FIXME @shykes: this seems redundant, but is very old, I'm leaving it in case
 | 
				
			||||||
 | 
						// there is a side effect I'm not seeing.
 | 
				
			||||||
 | 
						// defer container.stdin.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container.State.Running {
 | 
						if container.State.Running {
 | 
				
			||||||
		t.Errorf("Container shouldn't be running")
 | 
							t.Errorf("Container shouldn't be running")
 | 
				
			||||||
| 
						 | 
					@ -490,22 +481,35 @@ func TestKillDifferentUser(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test that creating a container with a volume doesn't crash. Regression test for #995.
 | 
					// Test that creating a container with a volume doesn't crash. Regression test for #995.
 | 
				
			||||||
func TestCreateVolume(t *testing.T) {
 | 
					func TestCreateVolume(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, hc, _, err := ParseRun([]string{"-v", "/var/lib/data", GetTestImage(runtime).ID, "echo", "hello", "world"}, nil)
 | 
						config, hc, _, err := docker.ParseRun([]string{"-v", "/var/lib/data", unitTestImageID, "echo", "hello", "world"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c, _, err := runtime.Create(config, "")
 | 
						jobCreate := eng.Job("create")
 | 
				
			||||||
	if err != nil {
 | 
						if err := jobCreate.ImportEnv(config); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer runtime.Destroy(c)
 | 
						var id string
 | 
				
			||||||
	c.hostConfig = hc
 | 
						jobCreate.StdoutParseString(&id)
 | 
				
			||||||
	if err := c.Start(); err != nil {
 | 
						if err := jobCreate.Run(); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						jobStart := eng.Job("start", id)
 | 
				
			||||||
 | 
						if err := jobStart.ImportEnv(hc); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := jobStart.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// FIXME: this hack can be removed once Wait is a job
 | 
				
			||||||
 | 
						c := runtime.Get(id)
 | 
				
			||||||
 | 
						if c == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Couldn't retrieve container %s from runtime", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	c.WaitTimeout(500 * time.Millisecond)
 | 
						c.WaitTimeout(500 * time.Millisecond)
 | 
				
			||||||
	c.Wait()
 | 
						c.Wait()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -513,7 +517,7 @@ func TestCreateVolume(t *testing.T) {
 | 
				
			||||||
func TestKill(t *testing.T) {
 | 
					func TestKill(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"sleep", "2"},
 | 
							Cmd:   []string{"sleep", "2"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -557,7 +561,7 @@ func TestExitCode(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	trueContainer, _, err := runtime.Create(&Config{
 | 
						trueContainer, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"/bin/true", ""},
 | 
							Cmd:   []string{"/bin/true", ""},
 | 
				
			||||||
	}, "")
 | 
						}, "")
 | 
				
			||||||
| 
						 | 
					@ -572,7 +576,7 @@ func TestExitCode(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
 | 
							t.Errorf("Unexpected exit code %d (expected 0)", trueContainer.State.ExitCode)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	falseContainer, _, err := runtime.Create(&Config{
 | 
						falseContainer, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"/bin/false", ""},
 | 
							Cmd:   []string{"/bin/false", ""},
 | 
				
			||||||
	}, "")
 | 
						}, "")
 | 
				
			||||||
| 
						 | 
					@ -591,7 +595,7 @@ func TestExitCode(t *testing.T) {
 | 
				
			||||||
func TestRestart(t *testing.T) {
 | 
					func TestRestart(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"echo", "-n", "foobar"},
 | 
							Cmd:   []string{"echo", "-n", "foobar"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -622,7 +626,7 @@ func TestRestart(t *testing.T) {
 | 
				
			||||||
func TestRestartStdin(t *testing.T) {
 | 
					func TestRestartStdin(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"cat"},
 | 
							Cmd:   []string{"cat"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -700,7 +704,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Default user must be root
 | 
						// Default user must be root
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -719,7 +723,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set a username
 | 
						// Set a username
 | 
				
			||||||
	container, _, err = runtime.Create(&Config{
 | 
						container, _, err = runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -740,7 +744,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set a UID
 | 
						// Set a UID
 | 
				
			||||||
	container, _, err = runtime.Create(&Config{
 | 
						container, _, err = runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -761,7 +765,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set a different user by uid
 | 
						// Set a different user by uid
 | 
				
			||||||
	container, _, err = runtime.Create(&Config{
 | 
						container, _, err = runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -784,7 +788,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set a different user by username
 | 
						// Set a different user by username
 | 
				
			||||||
	container, _, err = runtime.Create(&Config{
 | 
						container, _, err = runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -805,7 +809,7 @@ func TestUser(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test an wrong username
 | 
						// Test an wrong username
 | 
				
			||||||
	container, _, err = runtime.Create(&Config{
 | 
						container, _, err = runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"id"},
 | 
							Cmd:   []string{"id"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -827,7 +831,7 @@ func TestMultipleContainers(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container1, _, err := runtime.Create(&Config{
 | 
						container1, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"sleep", "2"},
 | 
							Cmd:   []string{"sleep", "2"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -838,7 +842,7 @@ func TestMultipleContainers(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer runtime.Destroy(container1)
 | 
						defer runtime.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _, err := runtime.Create(&Config{
 | 
						container2, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"sleep", "2"},
 | 
							Cmd:   []string{"sleep", "2"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -882,7 +886,7 @@ func TestMultipleContainers(t *testing.T) {
 | 
				
			||||||
func TestStdin(t *testing.T) {
 | 
					func TestStdin(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"cat"},
 | 
							Cmd:   []string{"cat"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -927,7 +931,7 @@ func TestStdin(t *testing.T) {
 | 
				
			||||||
func TestTty(t *testing.T) {
 | 
					func TestTty(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"cat"},
 | 
							Cmd:   []string{"cat"},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -974,7 +978,7 @@ func TestEnv(t *testing.T) {
 | 
				
			||||||
	os.Setenv("TRICKY", "tri\ncky\n")
 | 
						os.Setenv("TRICKY", "tri\ncky\n")
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(runtime).ID, "env"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1028,7 +1032,7 @@ func TestEntrypoint(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:      GetTestImage(runtime).ID,
 | 
								Image:      GetTestImage(runtime).ID,
 | 
				
			||||||
			Entrypoint: []string{"/bin/echo"},
 | 
								Entrypoint: []string{"/bin/echo"},
 | 
				
			||||||
			Cmd:        []string{"-n", "foobar"},
 | 
								Cmd:        []string{"-n", "foobar"},
 | 
				
			||||||
| 
						 | 
					@ -1052,7 +1056,7 @@ func TestEntrypointNoCmd(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:      GetTestImage(runtime).ID,
 | 
								Image:      GetTestImage(runtime).ID,
 | 
				
			||||||
			Entrypoint: []string{"/bin/echo", "foobar"},
 | 
								Entrypoint: []string{"/bin/echo", "foobar"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -1071,96 +1075,11 @@ func TestEntrypointNoCmd(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func grepFile(t *testing.T, path string, pattern string) {
 | 
					 | 
				
			||||||
	f, err := os.Open(path)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer f.Close()
 | 
					 | 
				
			||||||
	r := bufio.NewReader(f)
 | 
					 | 
				
			||||||
	var (
 | 
					 | 
				
			||||||
		line string
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	err = nil
 | 
					 | 
				
			||||||
	for err == nil {
 | 
					 | 
				
			||||||
		line, err = r.ReadString('\n')
 | 
					 | 
				
			||||||
		if strings.Contains(line, pattern) == true {
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLXCConfig(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
	// Memory is allocated randomly for testing
 | 
					 | 
				
			||||||
	rand.Seed(time.Now().UTC().UnixNano())
 | 
					 | 
				
			||||||
	memMin := 33554432
 | 
					 | 
				
			||||||
	memMax := 536870912
 | 
					 | 
				
			||||||
	mem := memMin + rand.Intn(memMax-memMin)
 | 
					 | 
				
			||||||
	// CPU shares as well
 | 
					 | 
				
			||||||
	cpuMin := 100
 | 
					 | 
				
			||||||
	cpuMax := 10000
 | 
					 | 
				
			||||||
	cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
 | 
					 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
					 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
					 | 
				
			||||||
		Cmd:   []string{"/bin/true"},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Hostname:  "foobar",
 | 
					 | 
				
			||||||
		Memory:    int64(mem),
 | 
					 | 
				
			||||||
		CpuShares: int64(cpu),
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
		"",
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer runtime.Destroy(container)
 | 
					 | 
				
			||||||
	container.generateLXCConfig()
 | 
					 | 
				
			||||||
	grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
 | 
					 | 
				
			||||||
	grepFile(t, container.lxcConfigPath(),
 | 
					 | 
				
			||||||
		fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
 | 
					 | 
				
			||||||
	grepFile(t, container.lxcConfigPath(),
 | 
					 | 
				
			||||||
		fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCustomLxcConfig(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
					 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
					 | 
				
			||||||
		Cmd:   []string{"/bin/true"},
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Hostname: "foobar",
 | 
					 | 
				
			||||||
	},
 | 
					 | 
				
			||||||
		"",
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer runtime.Destroy(container)
 | 
					 | 
				
			||||||
	container.hostConfig = &HostConfig{LxcConf: []KeyValuePair{
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Key:   "lxc.utsname",
 | 
					 | 
				
			||||||
			Value: "docker",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Key:   "lxc.cgroup.cpuset.cpus",
 | 
					 | 
				
			||||||
			Value: "0,1",
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	container.generateLXCConfig()
 | 
					 | 
				
			||||||
	grepFile(t, container.lxcConfigPath(), "lxc.utsname = docker")
 | 
					 | 
				
			||||||
	grepFile(t, container.lxcConfigPath(), "lxc.cgroup.cpuset.cpus = 0,1")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func BenchmarkRunSequencial(b *testing.B) {
 | 
					func BenchmarkRunSequencial(b *testing.B) {
 | 
				
			||||||
	runtime := mkRuntime(b)
 | 
						runtime := mkRuntime(b)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	for i := 0; i < b.N; i++ {
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
		container, _, err := runtime.Create(&Config{
 | 
							container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
			Image: GetTestImage(runtime).ID,
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:   []string{"echo", "-n", "foo"},
 | 
								Cmd:   []string{"echo", "-n", "foo"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -1193,7 +1112,7 @@ func BenchmarkRunParallel(b *testing.B) {
 | 
				
			||||||
		complete := make(chan error)
 | 
							complete := make(chan error)
 | 
				
			||||||
		tasks = append(tasks, complete)
 | 
							tasks = append(tasks, complete)
 | 
				
			||||||
		go func(i int, complete chan error) {
 | 
							go func(i int, complete chan error) {
 | 
				
			||||||
			container, _, err := runtime.Create(&Config{
 | 
								container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
				Image: GetTestImage(runtime).ID,
 | 
									Image: GetTestImage(runtime).ID,
 | 
				
			||||||
				Cmd:   []string{"echo", "-n", "foo"},
 | 
									Cmd:   []string{"echo", "-n", "foo"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
| 
						 | 
					@ -1244,11 +1163,12 @@ func tempDir(t *testing.T) string {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test for #1737
 | 
					// Test for #1737
 | 
				
			||||||
func TestCopyVolumeUidGid(t *testing.T) {
 | 
					func TestCopyVolumeUidGid(t *testing.T) {
 | 
				
			||||||
	r := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(r)
 | 
						r := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						defer r.Nuke()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add directory not owned by root
 | 
						// Add directory not owned by root
 | 
				
			||||||
	container1, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
 | 
						container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello && touch /hello/test.txt && chown daemon.daemon /hello"}, t)
 | 
				
			||||||
	defer r.Destroy(container1)
 | 
						defer r.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container1.State.Running {
 | 
						if container1.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -1261,11 +1181,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Container shouldn't be running")
 | 
							t.Errorf("Container shouldn't be running")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rwTar, err := container1.ExportRw()
 | 
						img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	img, err := r.graph.Create(rwTar, container1, "unit test commited image", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1273,7 +1189,7 @@ func TestCopyVolumeUidGid(t *testing.T) {
 | 
				
			||||||
	// Test that the uid and gid is copied from the image to the volume
 | 
						// Test that the uid and gid is copied from the image to the volume
 | 
				
			||||||
	tmpDir1 := tempDir(t)
 | 
						tmpDir1 := tempDir(t)
 | 
				
			||||||
	defer os.RemoveAll(tmpDir1)
 | 
						defer os.RemoveAll(tmpDir1)
 | 
				
			||||||
	stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "stat", "-c", "%U %G", "/hello"}, t)
 | 
						stdout1, _ := runContainer(eng, r, []string{"-v", "/hello", img.ID, "stat", "-c", "%U %G", "/hello"}, t)
 | 
				
			||||||
	if !strings.Contains(stdout1, "daemon daemon") {
 | 
						if !strings.Contains(stdout1, "daemon daemon") {
 | 
				
			||||||
		t.Fatal("Container failed to transfer uid and gid to volume")
 | 
							t.Fatal("Container failed to transfer uid and gid to volume")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1281,11 +1197,12 @@ func TestCopyVolumeUidGid(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Test for #1582
 | 
					// Test for #1582
 | 
				
			||||||
func TestCopyVolumeContent(t *testing.T) {
 | 
					func TestCopyVolumeContent(t *testing.T) {
 | 
				
			||||||
	r := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(r)
 | 
						r := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						defer r.Nuke()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Put some content in a directory of a container and commit it
 | 
						// Put some content in a directory of a container and commit it
 | 
				
			||||||
	container1, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
 | 
						container1, _, _ := mkContainer(r, []string{"_", "/bin/sh", "-c", "mkdir -p /hello/local && echo hello > /hello/local/world"}, t)
 | 
				
			||||||
	defer r.Destroy(container1)
 | 
						defer r.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if container1.State.Running {
 | 
						if container1.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -1298,11 +1215,7 @@ func TestCopyVolumeContent(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Container shouldn't be running")
 | 
							t.Errorf("Container shouldn't be running")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rwTar, err := container1.ExportRw()
 | 
						img, err := r.Commit(container1, "", "", "unit test commited image", "", nil)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	img, err := r.graph.Create(rwTar, container1, "unit test commited image", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1310,31 +1223,33 @@ func TestCopyVolumeContent(t *testing.T) {
 | 
				
			||||||
	// Test that the content is copied from the image to the volume
 | 
						// Test that the content is copied from the image to the volume
 | 
				
			||||||
	tmpDir1 := tempDir(t)
 | 
						tmpDir1 := tempDir(t)
 | 
				
			||||||
	defer os.RemoveAll(tmpDir1)
 | 
						defer os.RemoveAll(tmpDir1)
 | 
				
			||||||
	stdout1, _ := runContainer(r, []string{"-v", "/hello", img.ID, "find", "/hello"}, t)
 | 
						stdout1, _ := runContainer(eng, r, []string{"-v", "/hello", img.ID, "find", "/hello"}, t)
 | 
				
			||||||
	if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
 | 
						if !(strings.Contains(stdout1, "/hello/local/world") && strings.Contains(stdout1, "/hello/local")) {
 | 
				
			||||||
		t.Fatal("Container failed to transfer content to volume")
 | 
							t.Fatal("Container failed to transfer content to volume")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBindMounts(t *testing.T) {
 | 
					func TestBindMounts(t *testing.T) {
 | 
				
			||||||
	r := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(r)
 | 
						r := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						defer r.Nuke()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmpDir := tempDir(t)
 | 
						tmpDir := tempDir(t)
 | 
				
			||||||
	defer os.RemoveAll(tmpDir)
 | 
						defer os.RemoveAll(tmpDir)
 | 
				
			||||||
	writeFile(path.Join(tmpDir, "touch-me"), "", t)
 | 
						writeFile(path.Join(tmpDir, "touch-me"), "", t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test reading from a read-only bind mount
 | 
						// Test reading from a read-only bind mount
 | 
				
			||||||
	stdout, _ := runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
 | 
						stdout, _ := runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:/tmp:ro", tmpDir), "_", "ls", "/tmp"}, t)
 | 
				
			||||||
	if !strings.Contains(stdout, "touch-me") {
 | 
						if !strings.Contains(stdout, "touch-me") {
 | 
				
			||||||
		t.Fatal("Container failed to read from bind mount")
 | 
							t.Fatal("Container failed to read from bind mount")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// test writing to bind mount
 | 
						// test writing to bind mount
 | 
				
			||||||
	runContainer(r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
 | 
						runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:/tmp:rw", tmpDir), "_", "touch", "/tmp/holla"}, t)
 | 
				
			||||||
	readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
 | 
						readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// test mounting to an illegal destination directory
 | 
						// test mounting to an illegal destination directory
 | 
				
			||||||
	if _, err := runContainer(r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "_", "ls", "."}, nil); err == nil {
 | 
						if _, err := runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "_", "ls", "."}, nil); err == nil {
 | 
				
			||||||
		t.Fatal("Container bind mounted illegal directory")
 | 
							t.Fatal("Container bind mounted illegal directory")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1344,7 +1259,7 @@ func TestFromVolumesInReadonlyMode(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:   GetTestImage(runtime).ID,
 | 
								Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:     []string{"/bin/echo", "-n", "foobar"},
 | 
								Cmd:     []string{"/bin/echo", "-n", "foobar"},
 | 
				
			||||||
			Volumes: map[string]struct{}{"/test": {}},
 | 
								Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
| 
						 | 
					@ -1364,7 +1279,7 @@ func TestFromVolumesInReadonlyMode(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _, err := runtime.Create(
 | 
						container2, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:       GetTestImage(runtime).ID,
 | 
								Image:       GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
								Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
				
			||||||
			VolumesFrom: container.ID + ":ro",
 | 
								VolumesFrom: container.ID + ":ro",
 | 
				
			||||||
| 
						 | 
					@ -1405,7 +1320,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:   GetTestImage(runtime).ID,
 | 
								Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:     []string{"/bin/echo", "-n", "foobar"},
 | 
								Cmd:     []string{"/bin/echo", "-n", "foobar"},
 | 
				
			||||||
			Volumes: map[string]struct{}{"/test": {}},
 | 
								Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
| 
						 | 
					@ -1425,7 +1340,7 @@ func TestVolumesFromReadonlyMount(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _, err := runtime.Create(
 | 
						container2, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:       GetTestImage(runtime).ID,
 | 
								Image:       GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
								Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
				
			||||||
			VolumesFrom: container.ID,
 | 
								VolumesFrom: container.ID,
 | 
				
			||||||
| 
						 | 
					@ -1461,7 +1376,7 @@ func TestRestartWithVolumes(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image:   GetTestImage(runtime).ID,
 | 
							Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:     []string{"echo", "-n", "foobar"},
 | 
							Cmd:     []string{"echo", "-n", "foobar"},
 | 
				
			||||||
		Volumes: map[string]struct{}{"/test": {}},
 | 
							Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
| 
						 | 
					@ -1505,7 +1420,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image:   GetTestImage(runtime).ID,
 | 
							Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
							Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
				
			||||||
		Volumes: map[string]struct{}{"/test": {}},
 | 
							Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
| 
						 | 
					@ -1534,7 +1449,7 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _, err := runtime.Create(
 | 
						container2, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:       GetTestImage(runtime).ID,
 | 
								Image:       GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:         []string{"cat", "/test/foo"},
 | 
								Cmd:         []string{"cat", "/test/foo"},
 | 
				
			||||||
			VolumesFrom: container.ID,
 | 
								VolumesFrom: container.ID,
 | 
				
			||||||
| 
						 | 
					@ -1568,26 +1483,42 @@ func TestVolumesFromWithVolumes(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 | 
					func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, hc, _, err := ParseRun([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
 | 
						config, hc, _, err := docker.ParseRun([]string{"-n=false", GetTestImage(runtime).ID, "ip", "addr", "show"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c, _, err := runtime.Create(config, "")
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						jobCreate := eng.Job("create")
 | 
				
			||||||
 | 
						if err := jobCreate.ImportEnv(config); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						var id string
 | 
				
			||||||
 | 
						jobCreate.StdoutParseString(&id)
 | 
				
			||||||
 | 
						if err := jobCreate.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// FIXME: this hack can be removed once Wait is a job
 | 
				
			||||||
 | 
						c := runtime.Get(id)
 | 
				
			||||||
 | 
						if c == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Couldn't retrieve container %s from runtime", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	stdout, err := c.StdoutPipe()
 | 
						stdout, err := c.StdoutPipe()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer runtime.Destroy(c)
 | 
					
 | 
				
			||||||
	c.hostConfig = hc
 | 
						jobStart := eng.Job("start", id)
 | 
				
			||||||
	if err := c.Start(); err != nil {
 | 
						if err := jobStart.ImportEnv(hc); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := jobStart.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.WaitTimeout(500 * time.Millisecond)
 | 
						c.WaitTimeout(500 * time.Millisecond)
 | 
				
			||||||
	c.Wait()
 | 
						c.Wait()
 | 
				
			||||||
	output, err := ioutil.ReadAll(stdout)
 | 
						output, err := ioutil.ReadAll(stdout)
 | 
				
			||||||
| 
						 | 
					@ -1602,37 +1533,40 @@ func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
 | 
				
			||||||
	if !strings.HasSuffix(interfaces[0], ": lo") {
 | 
						if !strings.HasSuffix(interfaces[0], ": lo") {
 | 
				
			||||||
		t.Fatalf("Wrong interface in test container: expected [*: lo], got %s", interfaces)
 | 
							t.Fatalf("Wrong interface in test container: expected [*: lo], got %s", interfaces)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPrivilegedCanMknod(t *testing.T) {
 | 
					func TestPrivilegedCanMknod(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if output, _ := runContainer(runtime, []string{"-privileged", "_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" {
 | 
						defer runtime.Nuke()
 | 
				
			||||||
 | 
						if output, _ := runContainer(eng, runtime, []string{"-privileged", "_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" {
 | 
				
			||||||
		t.Fatal("Could not mknod into privileged container")
 | 
							t.Fatal("Could not mknod into privileged container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPrivilegedCanMount(t *testing.T) {
 | 
					func TestPrivilegedCanMount(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if output, _ := runContainer(runtime, []string{"-privileged", "_", "sh", "-c", "mount -t tmpfs none /tmp && echo ok"}, t); output != "ok\n" {
 | 
						defer runtime.Nuke()
 | 
				
			||||||
 | 
						if output, _ := runContainer(eng, runtime, []string{"-privileged", "_", "sh", "-c", "mount -t tmpfs none /tmp && echo ok"}, t); output != "ok\n" {
 | 
				
			||||||
		t.Fatal("Could not mount into privileged container")
 | 
							t.Fatal("Could not mount into privileged container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPrivilegedCannotMknod(t *testing.T) {
 | 
					func TestPrivilegedCannotMknod(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if output, _ := runContainer(runtime, []string{"_", "sh", "-c", "mknod /tmp/sda b 8 0 || echo ok"}, t); output != "ok\n" {
 | 
						defer runtime.Nuke()
 | 
				
			||||||
 | 
						if output, _ := runContainer(eng, runtime, []string{"_", "sh", "-c", "mknod /tmp/sda b 8 0 || echo ok"}, t); output != "ok\n" {
 | 
				
			||||||
		t.Fatal("Could mknod into secure container")
 | 
							t.Fatal("Could mknod into secure container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPrivilegedCannotMount(t *testing.T) {
 | 
					func TestPrivilegedCannotMount(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if output, _ := runContainer(runtime, []string{"_", "sh", "-c", "mount -t tmpfs none /tmp || echo ok"}, t); output != "ok\n" {
 | 
						defer runtime.Nuke()
 | 
				
			||||||
 | 
						if output, _ := runContainer(eng, runtime, []string{"_", "sh", "-c", "mount -t tmpfs none /tmp || echo ok"}, t); output != "ok\n" {
 | 
				
			||||||
		t.Fatal("Could mount into secure container")
 | 
							t.Fatal("Could mount into secure container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1641,7 +1575,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image:   GetTestImage(runtime).ID,
 | 
							Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
							Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
				
			||||||
		Volumes: map[string]struct{}{"/test": {}},
 | 
							Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
| 
						 | 
					@ -1670,7 +1604,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _, err := runtime.Create(
 | 
						container2, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:   GetTestImage(runtime).ID,
 | 
								Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:     []string{"sh", "-c", "echo -n bar > /other/foo"},
 | 
								Cmd:     []string{"sh", "-c", "echo -n bar > /other/foo"},
 | 
				
			||||||
			Volumes: map[string]struct{}{"/other": {}},
 | 
								Volumes: map[string]struct{}{"/other": {}},
 | 
				
			||||||
| 
						 | 
					@ -1692,7 +1626,7 @@ func TestMultipleVolumesFrom(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container3, _, err := runtime.Create(
 | 
						container3, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:       GetTestImage(runtime).ID,
 | 
								Image:       GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
								Cmd:         []string{"/bin/echo", "-n", "foobar"},
 | 
				
			||||||
			VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
 | 
								VolumesFrom: strings.Join([]string{container.ID, container2.ID}, ","),
 | 
				
			||||||
| 
						 | 
					@ -1720,7 +1654,7 @@ func TestRestartGhost(t *testing.T) {
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(
 | 
						container, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image:   GetTestImage(runtime).ID,
 | 
								Image:   GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
								Cmd:     []string{"sh", "-c", "echo -n bar > /test/foo"},
 | 
				
			||||||
			Volumes: map[string]struct{}{"/test": {}},
 | 
								Volumes: map[string]struct{}{"/test": {}},
 | 
				
			||||||
							
								
								
									
										57
									
								
								integration/graph_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								integration/graph_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestMount(t *testing.T) {
 | 
				
			||||||
 | 
						graph := tempGraph(t)
 | 
				
			||||||
 | 
						defer os.RemoveAll(graph.Root)
 | 
				
			||||||
 | 
						archive, err := fakeTar()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						image, err := graph.Create(archive, nil, "Testing", "", nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tmp, err := ioutil.TempDir("", "docker-test-graph-mount-")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmp)
 | 
				
			||||||
 | 
						rootfs := path.Join(tmp, "rootfs")
 | 
				
			||||||
 | 
						if err := os.MkdirAll(rootfs, 0700); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						rw := path.Join(tmp, "rw")
 | 
				
			||||||
 | 
						if err := os.MkdirAll(rw, 0700); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := image.Mount(rootfs, rw); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// FIXME: test for mount contents
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err := docker.Unmount(rootfs); err != nil {
 | 
				
			||||||
 | 
								t.Error(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//FIXME: duplicate
 | 
				
			||||||
 | 
					func tempGraph(t *testing.T) *docker.Graph {
 | 
				
			||||||
 | 
						tmp, err := ioutil.TempDir("", "docker-graph-")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						graph, err := docker.NewGraph(tmp)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return graph
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								integration/iptables_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								integration/iptables_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/iptables"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this test should be a unit test.
 | 
				
			||||||
 | 
					// For example by mocking os/exec to make sure iptables is not actually called.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIptables(t *testing.T) {
 | 
				
			||||||
 | 
						if _, err := iptables.Raw("-L"); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						path := os.Getenv("PATH")
 | 
				
			||||||
 | 
						os.Setenv("PATH", "")
 | 
				
			||||||
 | 
						defer os.Setenv("PATH", path)
 | 
				
			||||||
 | 
						if _, err := iptables.Raw("-L"); err == nil {
 | 
				
			||||||
 | 
							t.Fatal("Not finding iptables in the PATH should cause an error")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@ package docker
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
	"github.com/dotcloud/docker/engine"
 | 
						"github.com/dotcloud/docker/engine"
 | 
				
			||||||
	"github.com/dotcloud/docker/sysinit"
 | 
						"github.com/dotcloud/docker/sysinit"
 | 
				
			||||||
	"github.com/dotcloud/docker/utils"
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
| 
						 | 
					@ -15,7 +16,6 @@ import (
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
					 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
| 
						 | 
					@ -32,42 +32,33 @@ const (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	globalRuntime   *Runtime
 | 
						// FIXME: globalRuntime is deprecated by globalEngine. All tests should be converted.
 | 
				
			||||||
 | 
						globalRuntime   *docker.Runtime
 | 
				
			||||||
 | 
						globalEngine    *engine.Engine
 | 
				
			||||||
	startFds        int
 | 
						startFds        int
 | 
				
			||||||
	startGoroutines int
 | 
						startGoroutines int
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func nuke(runtime *Runtime) error {
 | 
					// FIXME: nuke() is deprecated by Runtime.Nuke()
 | 
				
			||||||
	if nonuke := os.Getenv("NONUKE"); nonuke != "" {
 | 
					func nuke(runtime *docker.Runtime) error {
 | 
				
			||||||
		return nil
 | 
						return runtime.Nuke()
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var wg sync.WaitGroup
 | 
					 | 
				
			||||||
	for _, container := range runtime.List() {
 | 
					 | 
				
			||||||
		wg.Add(1)
 | 
					 | 
				
			||||||
		go func(c *Container) {
 | 
					 | 
				
			||||||
			c.Kill()
 | 
					 | 
				
			||||||
			wg.Done()
 | 
					 | 
				
			||||||
		}(container)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	wg.Wait()
 | 
					 | 
				
			||||||
	runtime.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	os.Remove(filepath.Join(runtime.config.Root, "linkgraph.db"))
 | 
					 | 
				
			||||||
	return os.RemoveAll(runtime.config.Root)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func cleanup(runtime *Runtime) error {
 | 
					// FIXME: cleanup and nuke are redundant.
 | 
				
			||||||
 | 
					func cleanup(eng *engine.Engine, t *testing.T) error {
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	for _, container := range runtime.List() {
 | 
						for _, container := range runtime.List() {
 | 
				
			||||||
		container.Kill()
 | 
							container.Kill()
 | 
				
			||||||
		runtime.Destroy(container)
 | 
							runtime.Destroy(container)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	images, err := runtime.graph.Map()
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
						images, err := srv.Images(true, "")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, image := range images {
 | 
						for _, image := range images {
 | 
				
			||||||
		if image.ID != unitTestImageID {
 | 
							if image.ID != unitTestImageID {
 | 
				
			||||||
			runtime.graph.Delete(image.ID)
 | 
								srv.ImageDelete(image.ID, false)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
| 
						 | 
					@ -136,10 +127,9 @@ func setupBaseImage() {
 | 
				
			||||||
		log.Fatalf("Unable to create a runtime for tests:", err)
 | 
							log.Fatalf("Unable to create a runtime for tests:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	srv := mkServerFromEngine(eng, log.New(os.Stderr, "", 0))
 | 
						srv := mkServerFromEngine(eng, log.New(os.Stderr, "", 0))
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If the unit test is not found, try to download it.
 | 
						// If the unit test is not found, try to download it.
 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID {
 | 
						if img, err := srv.ImageInspect(unitTestImageName); err != nil || img.ID != unitTestImageID {
 | 
				
			||||||
		// Retrieve the Image
 | 
							// Retrieve the Image
 | 
				
			||||||
		if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil, nil, true); err != nil {
 | 
							if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil, nil, true); err != nil {
 | 
				
			||||||
			log.Fatalf("Unable to pull the test image: %s", err)
 | 
								log.Fatalf("Unable to pull the test image: %s", err)
 | 
				
			||||||
| 
						 | 
					@ -154,8 +144,8 @@ func spawnGlobalDaemon() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	t := log.New(os.Stderr, "", 0)
 | 
						t := log.New(os.Stderr, "", 0)
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						globalEngine = eng
 | 
				
			||||||
	globalRuntime = srv.runtime
 | 
						globalRuntime = mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Spawn a Daemon
 | 
						// Spawn a Daemon
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -177,8 +167,8 @@ func spawnGlobalDaemon() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FIXME: test that ImagePull(json=true) send correct json output
 | 
					// FIXME: test that ImagePull(json=true) send correct json output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetTestImage(runtime *Runtime) *Image {
 | 
					func GetTestImage(runtime *docker.Runtime) *docker.Image {
 | 
				
			||||||
	imgs, err := runtime.graph.Map()
 | 
						imgs, err := runtime.Graph().Map()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatalf("Unable to get the test image:", err)
 | 
							log.Fatalf("Unable to get the test image:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -187,7 +177,7 @@ func GetTestImage(runtime *Runtime) *Image {
 | 
				
			||||||
			return image
 | 
								return image
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	log.Fatalf("Test image %v not found in %s: %s", unitTestImageID, runtime.graph.Root, imgs)
 | 
						log.Fatalf("Test image %v not found in %s: %s", unitTestImageID, runtime.Graph().Root, imgs)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,7 +190,7 @@ func TestRuntimeCreate(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"ls", "-al"},
 | 
							Cmd:   []string{"ls", "-al"},
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
| 
						 | 
					@ -241,13 +231,25 @@ func TestRuntimeCreate(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Exists() returned false for a newly created container")
 | 
							t.Errorf("Exists() returned false for a newly created container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test that conflict error displays correct details
 | 
				
			||||||
 | 
						testContainer, _, _ := runtime.Create(
 | 
				
			||||||
 | 
							&docker.Config{
 | 
				
			||||||
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
 | 
								Cmd:   []string{"ls", "-al"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							"conflictname",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						if _, _, err := runtime.Create(&docker.Config{Image: GetTestImage(runtime).ID, Cmd: []string{"ls", "-al"}}, testContainer.Name); err == nil || !strings.Contains(err.Error(), utils.TruncateID(testContainer.ID)) {
 | 
				
			||||||
 | 
							t.Fatalf("Name conflict error doesn't include the correct short id. Message was: %s", err.Error())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Make sure create with bad parameters returns an error
 | 
						// Make sure create with bad parameters returns an error
 | 
				
			||||||
	if _, _, err = runtime.Create(&Config{Image: GetTestImage(runtime).ID}, ""); err == nil {
 | 
						if _, _, err = runtime.Create(&docker.Config{Image: GetTestImage(runtime).ID}, ""); err == nil {
 | 
				
			||||||
		t.Fatal("Builder.Create should throw an error when Cmd is missing")
 | 
							t.Fatal("Builder.Create should throw an error when Cmd is missing")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, _, err := runtime.Create(
 | 
						if _, _, err := runtime.Create(
 | 
				
			||||||
		&Config{
 | 
							&docker.Config{
 | 
				
			||||||
			Image: GetTestImage(runtime).ID,
 | 
								Image: GetTestImage(runtime).ID,
 | 
				
			||||||
			Cmd:   []string{},
 | 
								Cmd:   []string{},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
| 
						 | 
					@ -256,7 +258,7 @@ func TestRuntimeCreate(t *testing.T) {
 | 
				
			||||||
		t.Fatal("Builder.Create should throw an error when Cmd is empty")
 | 
							t.Fatal("Builder.Create should throw an error when Cmd is empty")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config := &Config{
 | 
						config := &docker.Config{
 | 
				
			||||||
		Image:     GetTestImage(runtime).ID,
 | 
							Image:     GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:       []string{"/bin/ls"},
 | 
							Cmd:       []string{"/bin/ls"},
 | 
				
			||||||
		PortSpecs: []string{"80"},
 | 
							PortSpecs: []string{"80"},
 | 
				
			||||||
| 
						 | 
					@ -269,7 +271,7 @@ func TestRuntimeCreate(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// test expose 80:8000
 | 
						// test expose 80:8000
 | 
				
			||||||
	container, warnings, err := runtime.Create(&Config{
 | 
						container, warnings, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image:     GetTestImage(runtime).ID,
 | 
							Image:     GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:       []string{"ls", "-al"},
 | 
							Cmd:       []string{"ls", "-al"},
 | 
				
			||||||
		PortSpecs: []string{"80:8000"},
 | 
							PortSpecs: []string{"80:8000"},
 | 
				
			||||||
| 
						 | 
					@ -288,7 +290,7 @@ func TestDestroy(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, _, err := runtime.Create(&Config{
 | 
						container, _, err := runtime.Create(&docker.Config{
 | 
				
			||||||
		Image: GetTestImage(runtime).ID,
 | 
							Image: GetTestImage(runtime).ID,
 | 
				
			||||||
		Cmd:   []string{"ls", "-al"},
 | 
							Cmd:   []string{"ls", "-al"},
 | 
				
			||||||
	}, "")
 | 
						}, "")
 | 
				
			||||||
| 
						 | 
					@ -315,12 +317,6 @@ func TestDestroy(t *testing.T) {
 | 
				
			||||||
		t.Errorf("Unable to get newly created container")
 | 
							t.Errorf("Unable to get newly created container")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Make sure the container root directory does not exist anymore
 | 
					 | 
				
			||||||
	_, err = os.Stat(container.root)
 | 
					 | 
				
			||||||
	if err == nil || !os.IsNotExist(err) {
 | 
					 | 
				
			||||||
		t.Errorf("Container root directory still exists after destroy")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Test double destroy
 | 
						// Test double destroy
 | 
				
			||||||
	if err := runtime.Destroy(container); err == nil {
 | 
						if err := runtime.Destroy(container); err == nil {
 | 
				
			||||||
		// It should have failed
 | 
							// It should have failed
 | 
				
			||||||
| 
						 | 
					@ -332,13 +328,13 @@ func TestGet(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						runtime := mkRuntime(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container1, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
						container1, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container1)
 | 
						defer runtime.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container2, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
						container2, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container2)
 | 
						defer runtime.Destroy(container2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container3, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
						container3, _, _ := mkContainer(runtime, []string{"_", "ls", "-al"}, t)
 | 
				
			||||||
	defer runtime.Destroy(container3)
 | 
						defer runtime.Destroy(container3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if runtime.Get(container1.ID) != container1 {
 | 
						if runtime.Get(container1.ID) != container1 {
 | 
				
			||||||
| 
						 | 
					@ -355,15 +351,21 @@ func TestGet(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container, string) {
 | 
					func startEchoServerContainer(t *testing.T, proto string) (*docker.Runtime, *docker.Container, string) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		err       error
 | 
							err     error
 | 
				
			||||||
		container *Container
 | 
							id      string
 | 
				
			||||||
		strPort   string
 | 
							strPort string
 | 
				
			||||||
		runtime   = mkRuntime(t)
 | 
							eng     = NewTestEngine(t)
 | 
				
			||||||
		port      = 5554
 | 
							runtime = mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
		p         Port
 | 
							port    = 5554
 | 
				
			||||||
 | 
							p       docker.Port
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								runtime.Nuke()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		port += 1
 | 
							port += 1
 | 
				
			||||||
| 
						 | 
					@ -376,37 +378,45 @@ func startEchoServerContainer(t *testing.T, proto string) (*Runtime, *Container,
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
 | 
								t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ep := make(map[Port]struct{}, 1)
 | 
							ep := make(map[docker.Port]struct{}, 1)
 | 
				
			||||||
		p = Port(fmt.Sprintf("%s/%s", strPort, proto))
 | 
							p = docker.Port(fmt.Sprintf("%s/%s", strPort, proto))
 | 
				
			||||||
		ep[p] = struct{}{}
 | 
							ep[p] = struct{}{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		container, _, err = runtime.Create(&Config{
 | 
							jobCreate := eng.Job("create")
 | 
				
			||||||
			Image:        GetTestImage(runtime).ID,
 | 
							jobCreate.Setenv("Image", unitTestImageID)
 | 
				
			||||||
			Cmd:          []string{"sh", "-c", cmd},
 | 
							jobCreate.SetenvList("Cmd", []string{"sh", "-c", cmd})
 | 
				
			||||||
			PortSpecs:    []string{fmt.Sprintf("%s/%s", strPort, proto)},
 | 
							jobCreate.SetenvList("PortSpecs", []string{fmt.Sprintf("%s/%s", strPort, proto)})
 | 
				
			||||||
			ExposedPorts: ep,
 | 
							jobCreate.SetenvJson("ExposedPorts", ep)
 | 
				
			||||||
		}, "")
 | 
							jobCreate.StdoutParseString(&id)
 | 
				
			||||||
		if err != nil {
 | 
							if err := jobCreate.Run(); err != nil {
 | 
				
			||||||
			nuke(runtime)
 | 
					 | 
				
			||||||
			t.Fatal(err)
 | 
								t.Fatal(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							// FIXME: this relies on the undocumented behavior of runtime.Create
 | 
				
			||||||
		if container != nil {
 | 
							// which will return a nil error AND container if the exposed ports
 | 
				
			||||||
 | 
							// are invalid. That behavior should be fixed!
 | 
				
			||||||
 | 
							if id != "" {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		t.Logf("Port %v already in use, trying another one", strPort)
 | 
							t.Logf("Port %v already in use, trying another one", strPort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container.hostConfig = &HostConfig{
 | 
						jobStart := eng.Job("start", id)
 | 
				
			||||||
		PortBindings: make(map[Port][]PortBinding),
 | 
						portBindings := make(map[docker.Port][]docker.PortBinding)
 | 
				
			||||||
	}
 | 
						portBindings[p] = []docker.PortBinding{
 | 
				
			||||||
	container.hostConfig.PortBindings[p] = []PortBinding{
 | 
					 | 
				
			||||||
		{},
 | 
							{},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := container.Start(); err != nil {
 | 
						if err := jobStart.SetenvJson("PortsBindings", portBindings); err != nil {
 | 
				
			||||||
		nuke(runtime)
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := jobStart.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container := runtime.Get(id)
 | 
				
			||||||
 | 
						if container == nil {
 | 
				
			||||||
 | 
							t.Fatalf("Couldn't fetch test container %s", id)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
 | 
						setTimeout(t, "Waiting for the container to be started timed out", 2*time.Second, func() {
 | 
				
			||||||
		for !container.State.Running {
 | 
							for !container.State.Running {
 | 
				
			||||||
| 
						 | 
					@ -507,14 +517,15 @@ func TestAllocateUDPPortLocalhost(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRestore(t *testing.T) {
 | 
					func TestRestore(t *testing.T) {
 | 
				
			||||||
	runtime1 := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime1)
 | 
						runtime1 := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						defer runtime1.Nuke()
 | 
				
			||||||
	// Create a container with one instance of docker
 | 
						// Create a container with one instance of docker
 | 
				
			||||||
	container1, _ := mkContainer(runtime1, []string{"_", "ls", "-al"}, t)
 | 
						container1, _, _ := mkContainer(runtime1, []string{"_", "ls", "-al"}, t)
 | 
				
			||||||
	defer runtime1.Destroy(container1)
 | 
						defer runtime1.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create a second container meant to be killed
 | 
						// Create a second container meant to be killed
 | 
				
			||||||
	container2, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
 | 
						container2, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
 | 
				
			||||||
	defer runtime1.Destroy(container2)
 | 
						defer runtime1.Destroy(container2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Start the container non blocking
 | 
						// Start the container non blocking
 | 
				
			||||||
| 
						 | 
					@ -548,12 +559,19 @@ func TestRestore(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Here are are simulating a docker restart - that is, reloading all containers
 | 
						// Here are are simulating a docker restart - that is, reloading all containers
 | 
				
			||||||
	// from scratch
 | 
						// from scratch
 | 
				
			||||||
	runtime1.config.AutoRestart = false
 | 
						root := eng.Root()
 | 
				
			||||||
	runtime2, err := NewRuntimeFromDirectory(runtime1.config)
 | 
						eng, err := engine.New(root)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer nuke(runtime2)
 | 
						job := eng.Job("initapi")
 | 
				
			||||||
 | 
						job.Setenv("Root", eng.Root())
 | 
				
			||||||
 | 
						job.SetenvBool("Autorestart", false)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						runtime2 := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if len(runtime2.List()) != 2 {
 | 
						if len(runtime2.List()) != 2 {
 | 
				
			||||||
		t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
 | 
							t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -578,14 +596,31 @@ func TestRestore(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestReloadContainerLinks(t *testing.T) {
 | 
					func TestReloadContainerLinks(t *testing.T) {
 | 
				
			||||||
	runtime1 := mkRuntime(t)
 | 
						// FIXME: here we don't use NewTestEngine because it calls initapi with Autorestart=false,
 | 
				
			||||||
 | 
						// and we want to set it to true.
 | 
				
			||||||
 | 
						root, err := newTestDirectory(unitTestStoreBase)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						eng, err := engine.New(root)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						job := eng.Job("initapi")
 | 
				
			||||||
 | 
						job.Setenv("Root", eng.Root())
 | 
				
			||||||
 | 
						job.SetenvBool("Autorestart", true)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						runtime1 := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	defer nuke(runtime1)
 | 
						defer nuke(runtime1)
 | 
				
			||||||
	// Create a container with one instance of docker
 | 
						// Create a container with one instance of docker
 | 
				
			||||||
	container1, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/sh"}, t)
 | 
						container1, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/sh"}, t)
 | 
				
			||||||
	defer runtime1.Destroy(container1)
 | 
						defer runtime1.Destroy(container1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Create a second container meant to be killed
 | 
						// Create a second container meant to be killed
 | 
				
			||||||
	container2, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
 | 
						container2, _, _ := mkContainer(runtime1, []string{"-i", "_", "/bin/cat"}, t)
 | 
				
			||||||
	defer runtime1.Destroy(container2)
 | 
						defer runtime1.Destroy(container2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Start the container non blocking
 | 
						// Start the container non blocking
 | 
				
			||||||
| 
						 | 
					@ -593,7 +628,9 @@ func TestReloadContainerLinks(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Add a link to container 2
 | 
						// Add a link to container 2
 | 
				
			||||||
	container1.hostConfig.Links = []string{"/" + container2.ID + ":first"}
 | 
						// FIXME @shykes: setting hostConfig.Links seems redundant with calling RegisterLink().
 | 
				
			||||||
 | 
						// Why do we need it @crosbymichael?
 | 
				
			||||||
 | 
						// container1.hostConfig.Links = []string{"/" + container2.ID + ":first"}
 | 
				
			||||||
	if err := runtime1.RegisterLink(container1, container2, "first"); err != nil {
 | 
						if err := runtime1.RegisterLink(container1, container2, "first"); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -615,12 +652,18 @@ func TestReloadContainerLinks(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Here are are simulating a docker restart - that is, reloading all containers
 | 
						// Here are are simulating a docker restart - that is, reloading all containers
 | 
				
			||||||
	// from scratch
 | 
						// from scratch
 | 
				
			||||||
	runtime1.config.AutoRestart = true
 | 
						eng, err = engine.New(root)
 | 
				
			||||||
	runtime2, err := NewRuntimeFromDirectory(runtime1.config)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer nuke(runtime2)
 | 
						job = eng.Job("initapi")
 | 
				
			||||||
 | 
						job.Setenv("Root", eng.Root())
 | 
				
			||||||
 | 
						job.SetenvBool("Autorestart", false)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						runtime2 := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	if len(runtime2.List()) != 2 {
 | 
						if len(runtime2.List()) != 2 {
 | 
				
			||||||
		t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
 | 
							t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -634,27 +677,32 @@ func TestReloadContainerLinks(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expected 2 container alive, %d found", runningCount)
 | 
							t.Fatalf("Expected 2 container alive, %d found", runningCount)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: we no longer test if containers were registered in the right order,
 | 
				
			||||||
 | 
						// because there is no public
 | 
				
			||||||
	// Make sure container 2 ( the child of container 1 ) was registered and started first
 | 
						// Make sure container 2 ( the child of container 1 ) was registered and started first
 | 
				
			||||||
	// with the runtime
 | 
						// with the runtime
 | 
				
			||||||
	first := runtime2.containers.Front()
 | 
						//
 | 
				
			||||||
	if first.Value.(*Container).ID != container2.ID {
 | 
						containers := runtime2.List()
 | 
				
			||||||
 | 
						if len(containers) == 0 {
 | 
				
			||||||
 | 
							t.Fatalf("Runtime has no containers")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						first := containers[0]
 | 
				
			||||||
 | 
						if first.ID != container2.ID {
 | 
				
			||||||
		t.Fatalf("Container 2 %s should be registered first in the runtime", container2.ID)
 | 
							t.Fatalf("Container 2 %s should be registered first in the runtime", container2.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Verify that the link is still registered in the runtime
 | 
						// Verify that the link is still registered in the runtime
 | 
				
			||||||
	entity := runtime2.containerGraph.Get(container1.Name)
 | 
						if c := runtime2.Get(container1.Name); c == nil {
 | 
				
			||||||
	if entity == nil {
 | 
							t.Fatal("Named container is no longer registered after restart")
 | 
				
			||||||
		t.Fatal("Entity should not be nil")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDefaultContainerName(t *testing.T) {
 | 
					func TestDefaultContainerName(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -666,29 +714,19 @@ func TestDefaultContainerName(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expect /some_name got %s", container.Name)
 | 
							t.Fatalf("Expect /some_name got %s", container.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paths := runtime.containerGraph.RefPaths(containerID)
 | 
						if c := runtime.Get("/some_name"); c == nil {
 | 
				
			||||||
	if paths == nil || len(paths) == 0 {
 | 
							t.Fatalf("Couldn't retrieve test container as /some_name")
 | 
				
			||||||
		t.Fatalf("Could not find edges for %s", containerID)
 | 
						} else if c.ID != containerID {
 | 
				
			||||||
	}
 | 
							t.Fatalf("Container /some_name has ID %s instead of %s", c.ID, containerID)
 | 
				
			||||||
	edge := paths[0]
 | 
					 | 
				
			||||||
	if edge.ParentID != "0" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected engine got %s", edge.ParentID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if edge.EntityID != containerID {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected %s got %s", containerID, edge.EntityID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if edge.Name != "some_name" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected some_name got %s", edge.Name)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRandomContainerName(t *testing.T) {
 | 
					func TestRandomContainerName(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -700,29 +738,19 @@ func TestRandomContainerName(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expected not empty container name")
 | 
							t.Fatalf("Expected not empty container name")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paths := runtime.containerGraph.RefPaths(containerID)
 | 
						if c := runtime.Get(container.Name); c == nil {
 | 
				
			||||||
	if paths == nil || len(paths) == 0 {
 | 
							log.Fatalf("Could not lookup container %s by its name", container.Name)
 | 
				
			||||||
		t.Fatalf("Could not find edges for %s", containerID)
 | 
						} else if c.ID != containerID {
 | 
				
			||||||
	}
 | 
							log.Fatalf("Looking up container name %s returned id %s instead of %s", container.Name, c.ID, containerID)
 | 
				
			||||||
	edge := paths[0]
 | 
					 | 
				
			||||||
	if edge.ParentID != "0" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected engine got %s", edge.ParentID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if edge.EntityID != containerID {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected %s got %s", containerID, edge.EntityID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if edge.Name == "" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected not empty container name")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestLinkChildContainer(t *testing.T) {
 | 
					func TestLinkChildContainer(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -738,7 +766,7 @@ func TestLinkChildContainer(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
 | 
							t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err = ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err = docker.ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -761,11 +789,10 @@ func TestLinkChildContainer(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetAllChildren(t *testing.T) {
 | 
					func TestGetAllChildren(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(runtime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -781,7 +808,7 @@ func TestGetAllChildren(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
 | 
							t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err = ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err = docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -813,19 +840,3 @@ func TestGetAllChildren(t *testing.T) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestGetFullName(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	name, err := runtime.getFullName("testing")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if name != "/testing" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected /testing got %s", name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if _, err := runtime.getFullName(""); err == nil {
 | 
					 | 
				
			||||||
		t.Fatal("Error should not be nil")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,32 +1,31 @@
 | 
				
			||||||
package docker
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
	"github.com/dotcloud/docker/utils"
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestContainerTagImageDelete(t *testing.T) {
 | 
					func TestContainerTagImageDelete(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialImages, err := srv.Images(false, "")
 | 
						initialImages, err := srv.Images(false, "")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest", "tag1", false); err != nil {
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest", "tag1", unitTestImageName, false); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest/docker", "tag2", unitTestImageName, false); err != nil {
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest/docker", "tag2", false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest:5000/docker", "tag3", unitTestImageName, false); err != nil {
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest:5000/docker", "tag3", false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,46 +81,43 @@ func TestContainerTagImageDelete(t *testing.T) {
 | 
				
			||||||
func TestCreateRm(t *testing.T) {
 | 
					func TestCreateRm(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id := createTestContainer(eng, config, t)
 | 
						id := createTestContainer(eng, config, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 1 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 1 {
 | 
				
			||||||
		t.Errorf("Expected 1 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 1 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = srv.ContainerDestroy(id, true, false); err != nil {
 | 
						if err = srv.ContainerDestroy(id, true, false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 0 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 0 {
 | 
				
			||||||
		t.Errorf("Expected 0 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 0 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateRmVolumes(t *testing.T) {
 | 
					func TestCreateRmVolumes(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, hostConfig, _, err := ParseRun([]string{"-v", "/srv", GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, hostConfig, _, err := docker.ParseRun([]string{"-v", "/srv", unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id := createTestContainer(eng, config, t)
 | 
						id := createTestContainer(eng, config, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 1 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 1 {
 | 
				
			||||||
		t.Errorf("Expected 1 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 1 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job := eng.Job("start", id)
 | 
						job := eng.Job("start", id)
 | 
				
			||||||
| 
						 | 
					@ -141,18 +137,17 @@ func TestCreateRmVolumes(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 0 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 0 {
 | 
				
			||||||
		t.Errorf("Expected 0 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 0 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCommit(t *testing.T) {
 | 
					func TestCommit(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, _, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
 | 
						config, _, _, err := docker.ParseRun([]string{unitTestImageID, "/bin/cat"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -167,18 +162,17 @@ func TestCommit(t *testing.T) {
 | 
				
			||||||
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 | 
					func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "/bin/cat"}, nil)
 | 
						config, hostConfig, _, err := docker.ParseRun([]string{unitTestImageID, "/bin/cat"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id := createTestContainer(eng, config, t)
 | 
						id := createTestContainer(eng, config, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 1 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 1 {
 | 
				
			||||||
		t.Errorf("Expected 1 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 1 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	job := eng.Job("start", id)
 | 
						job := eng.Job("start", id)
 | 
				
			||||||
| 
						 | 
					@ -214,21 +208,18 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(runtime.List()) != 0 {
 | 
						if c := srv.Containers(true, false, -1, "", ""); len(c) != 0 {
 | 
				
			||||||
		t.Errorf("Expected 0 container, %v found", len(runtime.List()))
 | 
							t.Errorf("Expected 0 container, %v found", len(c))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRunWithTooLowMemoryLimit(t *testing.T) {
 | 
					func TestRunWithTooLowMemoryLimit(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	runtime := srv.runtime
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
 | 
						// Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
 | 
				
			||||||
	job := eng.Job("create")
 | 
						job := eng.Job("create")
 | 
				
			||||||
	job.Setenv("Image", GetTestImage(runtime).ID)
 | 
						job.Setenv("Image", unitTestImageID)
 | 
				
			||||||
	job.Setenv("Memory", "524287")
 | 
						job.Setenv("Memory", "524287")
 | 
				
			||||||
	job.Setenv("CpuShares", "1000")
 | 
						job.Setenv("CpuShares", "1000")
 | 
				
			||||||
	job.SetenvList("Cmd", []string{"/bin/cat"})
 | 
						job.SetenvList("Cmd", []string{"/bin/cat"})
 | 
				
			||||||
| 
						 | 
					@ -239,163 +230,17 @@ func TestRunWithTooLowMemoryLimit(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestContainerTop(t *testing.T) {
 | 
					 | 
				
			||||||
	t.Skip("Fixme. Skipping test for now. Reported error: 'server_test.go:236: Expected 2 processes, found 1.'")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	c, _ := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "sleep 2"}, t)
 | 
					 | 
				
			||||||
	c, err := mkContainer(runtime, []string{"_", "/bin/sh", "-c", "sleep 2"}, t)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	defer runtime.Destroy(c)
 | 
					 | 
				
			||||||
	if err := c.Start(); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Give some time to the process to start
 | 
					 | 
				
			||||||
	c.WaitTimeout(500 * time.Millisecond)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !c.State.Running {
 | 
					 | 
				
			||||||
		t.Errorf("Container should be running")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	procs, err := srv.ContainerTop(c.ID, "")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(procs.Processes) != 2 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 2 processes, found %d.", len(procs.Processes))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pos := -1
 | 
					 | 
				
			||||||
	for i := 0; i < len(procs.Titles); i++ {
 | 
					 | 
				
			||||||
		if procs.Titles[i] == "CMD" {
 | 
					 | 
				
			||||||
			pos = i
 | 
					 | 
				
			||||||
			break
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if pos == -1 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected CMD, not found.")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if procs.Processes[0][pos] != "sh" && procs.Processes[0][pos] != "busybox" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `busybox` or `sh`, found %s.", procs.Processes[0][pos])
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if procs.Processes[1][pos] != "sh" && procs.Processes[1][pos] != "busybox" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `busybox` or `sh`, found %s.", procs.Processes[1][pos])
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestPools(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:     runtime,
 | 
					 | 
				
			||||||
		pullingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
		pushingPool: make(map[string]struct{}),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := srv.poolAdd("pull", "test1")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolAdd("pull", "test2")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolAdd("push", "test1")
 | 
					 | 
				
			||||||
	if err == nil || err.Error() != "pull test1 is already in progress" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `pull test1 is already in progress`")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolAdd("pull", "test1")
 | 
					 | 
				
			||||||
	if err == nil || err.Error() != "pull test1 is already in progress" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `pull test1 is already in progress`")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolAdd("wait", "test3")
 | 
					 | 
				
			||||||
	if err == nil || err.Error() != "Unknown pool type" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `Unknown pool type`")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = srv.poolRemove("pull", "test2")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolRemove("pull", "test2")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolRemove("pull", "test1")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolRemove("push", "test1")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = srv.poolRemove("wait", "test3")
 | 
					 | 
				
			||||||
	if err == nil || err.Error() != "Unknown pool type" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected `Unknown pool type`")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLogEvent(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
	srv := &Server{
 | 
					 | 
				
			||||||
		runtime:   runtime,
 | 
					 | 
				
			||||||
		events:    make([]utils.JSONMessage, 0, 64),
 | 
					 | 
				
			||||||
		listeners: make(map[string]chan utils.JSONMessage),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv.LogEvent("fakeaction", "fakeid", "fakeimage")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	listener := make(chan utils.JSONMessage)
 | 
					 | 
				
			||||||
	srv.Lock()
 | 
					 | 
				
			||||||
	srv.listeners["test"] = listener
 | 
					 | 
				
			||||||
	srv.Unlock()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv.LogEvent("fakeaction2", "fakeid", "fakeimage")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(srv.events) != 2 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 2 events, found %d", len(srv.events))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	go func() {
 | 
					 | 
				
			||||||
		time.Sleep(200 * time.Millisecond)
 | 
					 | 
				
			||||||
		srv.LogEvent("fakeaction3", "fakeid", "fakeimage")
 | 
					 | 
				
			||||||
		time.Sleep(200 * time.Millisecond)
 | 
					 | 
				
			||||||
		srv.LogEvent("fakeaction4", "fakeid", "fakeimage")
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	setTimeout(t, "Listening for events timed out", 2*time.Second, func() {
 | 
					 | 
				
			||||||
		for i := 2; i < 4; i++ {
 | 
					 | 
				
			||||||
			event := <-listener
 | 
					 | 
				
			||||||
			if event != srv.events[i] {
 | 
					 | 
				
			||||||
				t.Fatalf("Event received it different than expected")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestRmi(t *testing.T) {
 | 
					func TestRmi(t *testing.T) {
 | 
				
			||||||
	eng := NewTestEngine(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	srv := mkServerFromEngine(eng, t)
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	runtime := srv.runtime
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialImages, err := srv.Images(false, "")
 | 
						initialImages, err := srv.Images(false, "")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	config, hostConfig, _, err := ParseRun([]string{GetTestImage(runtime).ID, "echo test"}, nil)
 | 
						config, hostConfig, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -471,19 +316,19 @@ func TestRmi(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestImagesFilter(t *testing.T) {
 | 
					func TestImagesFilter(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer nuke(mkRuntimeFromEngine(eng, t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest", "tag1", unitTestImageName, false); err != nil {
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest", "tag1", false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest/docker", "tag2", unitTestImageName, false); err != nil {
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest/docker", "tag2", false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if err := srv.runtime.repositories.Set("utest:5000/docker", "tag3", unitTestImageName, false); err != nil {
 | 
						if err := srv.ContainerTag(unitTestImageName, "utest:5000/docker", "tag3", false); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -525,9 +370,9 @@ func TestImagesFilter(t *testing.T) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestImageInsert(t *testing.T) {
 | 
					func TestImageInsert(t *testing.T) {
 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
	defer nuke(runtime)
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
	sf := utils.NewStreamFormatter(true)
 | 
						sf := utils.NewStreamFormatter(true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// bad image name fails
 | 
						// bad image name fails
 | 
				
			||||||
| 
						 | 
					@ -536,12 +381,12 @@ func TestImageInsert(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// bad url fails
 | 
						// bad url fails
 | 
				
			||||||
	if err := srv.ImageInsert(GetTestImage(runtime).ID, "http://bad_host_name_that_will_totally_fail.com/", "/foo", ioutil.Discard, sf); err == nil {
 | 
						if err := srv.ImageInsert(unitTestImageID, "http://bad_host_name_that_will_totally_fail.com/", "/foo", ioutil.Discard, sf); err == nil {
 | 
				
			||||||
		t.Fatal("expected an error and got none")
 | 
							t.Fatal("expected an error and got none")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// success returns nil
 | 
						// success returns nil
 | 
				
			||||||
	if err := srv.ImageInsert(GetTestImage(runtime).ID, "https://www.docker.io/static/img/docker-top-logo.png", "/foo", ioutil.Discard, sf); err != nil {
 | 
						if err := srv.ImageInsert(unitTestImageID, "https://www.docker.io/static/img/docker-top-logo.png", "/foo", ioutil.Discard, sf); err != nil {
 | 
				
			||||||
		t.Fatalf("expected no error, but got %v", err)
 | 
							t.Fatalf("expected no error, but got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								integration/sorter_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								integration/sorter_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServerListOrderedImagesByCreationDate(t *testing.T) {
 | 
				
			||||||
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := generateImage("", srv); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						images, err := srv.Images(true, "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if images[0].Created < images[1].Created {
 | 
				
			||||||
 | 
							t.Error("Expected []APIImges to be ordered by most recent creation date.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) {
 | 
				
			||||||
 | 
						eng := NewTestEngine(t)
 | 
				
			||||||
 | 
						defer mkRuntimeFromEngine(eng, t).Nuke()
 | 
				
			||||||
 | 
						srv := mkServerFromEngine(eng, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := generateImage("bar", srv)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						time.Sleep(time.Second)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = generateImage("zed", srv)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						images, err := srv.Images(true, "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if images[0].RepoTags[0] != "repo:zed" && images[0].RepoTags[0] != "repo:bar" {
 | 
				
			||||||
 | 
							t.Errorf("Expected []APIImges to be ordered by most recent creation date. %s", images)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func generateImage(name string, srv *docker.Server) error {
 | 
				
			||||||
 | 
						archive, err := fakeTar()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv.ImageImport("-", "repo", name, archive, ioutil.Discard, utils.NewStreamFormatter(true))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										328
									
								
								integration/utils_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										328
									
								
								integration/utils_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,328 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"archive/tar"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/engine"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/http/httptest"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This file contains utility functions for docker's unit test suite.
 | 
				
			||||||
 | 
					// It has to be named XXX_test.go, apparently, in other to access private functions
 | 
				
			||||||
 | 
					// from other XXX_test.go functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create a temporary runtime suitable for unit testing.
 | 
				
			||||||
 | 
					// Call t.Fatal() at the first error.
 | 
				
			||||||
 | 
					func mkRuntime(f utils.Fataler) *docker.Runtime {
 | 
				
			||||||
 | 
						root, err := newTestDirectory(unitTestStoreBase)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							f.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						config := &docker.DaemonConfig{
 | 
				
			||||||
 | 
							Root:        root,
 | 
				
			||||||
 | 
							AutoRestart: false,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						r, err := docker.NewRuntimeFromDirectory(config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							f.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						r.UpdateCapabilities(true)
 | 
				
			||||||
 | 
						return r
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createNamedTestContainer(eng *engine.Engine, config *docker.Config, f utils.Fataler, name string) (shortId string) {
 | 
				
			||||||
 | 
						job := eng.Job("create", name)
 | 
				
			||||||
 | 
						if err := job.ImportEnv(config); err != nil {
 | 
				
			||||||
 | 
							f.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						job.StdoutParseString(&shortId)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							f.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createTestContainer(eng *engine.Engine, config *docker.Config, f utils.Fataler) (shortId string) {
 | 
				
			||||||
 | 
						return createNamedTestContainer(eng, config, f, "")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func startContainer(eng *engine.Engine, id string, t utils.Fataler) {
 | 
				
			||||||
 | 
						job := eng.Job("start", id)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerRun(eng *engine.Engine, id string, t utils.Fataler) {
 | 
				
			||||||
 | 
						startContainer(eng, id, t)
 | 
				
			||||||
 | 
						containerWait(eng, id, t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerFileExists(eng *engine.Engine, id, dir string, t utils.Fataler) bool {
 | 
				
			||||||
 | 
						c := getContainer(eng, id, t)
 | 
				
			||||||
 | 
						if err := c.EnsureMounted(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := os.Stat(path.Join(c.RootfsPath(), dir)); err != nil {
 | 
				
			||||||
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerAttach(eng *engine.Engine, id string, t utils.Fataler) (io.WriteCloser, io.ReadCloser) {
 | 
				
			||||||
 | 
						c := getContainer(eng, id, t)
 | 
				
			||||||
 | 
						i, err := c.StdinPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						o, err := c.StdoutPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return i, o
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerWait(eng *engine.Engine, id string, t utils.Fataler) int {
 | 
				
			||||||
 | 
						return getContainer(eng, id, t).Wait()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerWaitTimeout(eng *engine.Engine, id string, t utils.Fataler) error {
 | 
				
			||||||
 | 
						return getContainer(eng, id, t).WaitTimeout(500 * time.Millisecond)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerKill(eng *engine.Engine, id string, t utils.Fataler) {
 | 
				
			||||||
 | 
						if err := getContainer(eng, id, t).Kill(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerRunning(eng *engine.Engine, id string, t utils.Fataler) bool {
 | 
				
			||||||
 | 
						return getContainer(eng, id, t).State.Running
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerAssertExists(eng *engine.Engine, id string, t utils.Fataler) {
 | 
				
			||||||
 | 
						getContainer(eng, id, t)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func containerAssertNotExists(eng *engine.Engine, id string, t utils.Fataler) {
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						if c := runtime.Get(id); c != nil {
 | 
				
			||||||
 | 
							t.Fatal(fmt.Errorf("Container %s should not exist", id))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// assertHttpNotError expect the given response to not have an error.
 | 
				
			||||||
 | 
					// Otherwise the it causes the test to fail.
 | 
				
			||||||
 | 
					func assertHttpNotError(r *httptest.ResponseRecorder, t utils.Fataler) {
 | 
				
			||||||
 | 
						// Non-error http status are [200, 400)
 | 
				
			||||||
 | 
						if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest {
 | 
				
			||||||
 | 
							t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// assertHttpError expect the given response to have an error.
 | 
				
			||||||
 | 
					// Otherwise the it causes the test to fail.
 | 
				
			||||||
 | 
					func assertHttpError(r *httptest.ResponseRecorder, t utils.Fataler) {
 | 
				
			||||||
 | 
						// Non-error http status are [200, 400)
 | 
				
			||||||
 | 
						if !(r.Code < http.StatusOK || r.Code >= http.StatusBadRequest) {
 | 
				
			||||||
 | 
							t.Fatal(fmt.Errorf("Unexpected http success code: %v", r.Code))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getContainer(eng *engine.Engine, id string, t utils.Fataler) *docker.Container {
 | 
				
			||||||
 | 
						runtime := mkRuntimeFromEngine(eng, t)
 | 
				
			||||||
 | 
						c := runtime.Get(id)
 | 
				
			||||||
 | 
						if c == nil {
 | 
				
			||||||
 | 
							t.Fatal(fmt.Errorf("No such container: %s", id))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func mkServerFromEngine(eng *engine.Engine, t utils.Fataler) *docker.Server {
 | 
				
			||||||
 | 
						iSrv := eng.Hack_GetGlobalVar("httpapi.server")
 | 
				
			||||||
 | 
						if iSrv == nil {
 | 
				
			||||||
 | 
							panic("Legacy server field not set in engine")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						srv, ok := iSrv.(*docker.Server)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							panic("Legacy server field in engine does not cast to *docker.Server")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return srv
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func mkRuntimeFromEngine(eng *engine.Engine, t utils.Fataler) *docker.Runtime {
 | 
				
			||||||
 | 
						iRuntime := eng.Hack_GetGlobalVar("httpapi.runtime")
 | 
				
			||||||
 | 
						if iRuntime == nil {
 | 
				
			||||||
 | 
							panic("Legacy runtime field not set in engine")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						runtime, ok := iRuntime.(*docker.Runtime)
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							panic("Legacy runtime field in engine does not cast to *docker.Runtime")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return runtime
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewTestEngine(t utils.Fataler) *engine.Engine {
 | 
				
			||||||
 | 
						root, err := newTestDirectory(unitTestStoreBase)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						eng, err := engine.New(root)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Load default plugins
 | 
				
			||||||
 | 
						// (This is manually copied and modified from main() until we have a more generic plugin system)
 | 
				
			||||||
 | 
						job := eng.Job("initapi")
 | 
				
			||||||
 | 
						job.Setenv("Root", root)
 | 
				
			||||||
 | 
						job.SetenvBool("AutoRestart", false)
 | 
				
			||||||
 | 
						// TestGetEnabledCors and TestOptionsRoute require EnableCors=true
 | 
				
			||||||
 | 
						job.SetenvBool("EnableCors", true)
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return eng
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newTestDirectory(templateDir string) (dir string, err error) {
 | 
				
			||||||
 | 
						return utils.TestDirectory(templateDir)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getCallerName(depth int) string {
 | 
				
			||||||
 | 
						return utils.GetCallerName(depth)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Write `content` to the file at path `dst`, creating it if necessary,
 | 
				
			||||||
 | 
					// as well as any missing directories.
 | 
				
			||||||
 | 
					// The file is truncated if it already exists.
 | 
				
			||||||
 | 
					// Call t.Fatal() at the first error.
 | 
				
			||||||
 | 
					func writeFile(dst, content string, t *testing.T) {
 | 
				
			||||||
 | 
						// Create subdirectories if necessary
 | 
				
			||||||
 | 
						if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Write content (truncate if it exists)
 | 
				
			||||||
 | 
						if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Return the contents of file at path `src`.
 | 
				
			||||||
 | 
					// Call t.Fatal() at the first error (including if the file doesn't exist)
 | 
				
			||||||
 | 
					func readFile(src string, t *testing.T) (content string) {
 | 
				
			||||||
 | 
						f, err := os.Open(src)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						data, err := ioutil.ReadAll(f)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return string(data)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create a test container from the given runtime `r` and run arguments `args`.
 | 
				
			||||||
 | 
					// If the image name is "_", (eg. []string{"-i", "-t", "_", "bash"}, it is
 | 
				
			||||||
 | 
					// dynamically replaced by the current test image.
 | 
				
			||||||
 | 
					// The caller is responsible for destroying the container.
 | 
				
			||||||
 | 
					// Call t.Fatal() at the first error.
 | 
				
			||||||
 | 
					func mkContainer(r *docker.Runtime, args []string, t *testing.T) (*docker.Container, *docker.HostConfig, error) {
 | 
				
			||||||
 | 
						config, hc, _, err := docker.ParseRun(args, nil)
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err != nil && t != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if config.Image == "_" {
 | 
				
			||||||
 | 
							config.Image = GetTestImage(r).ID
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c, _, err := r.Create(config, "")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// NOTE: hostConfig is ignored.
 | 
				
			||||||
 | 
						// If `args` specify privileged mode, custom lxc conf, external mount binds,
 | 
				
			||||||
 | 
						// port redirects etc. they will be ignored.
 | 
				
			||||||
 | 
						// This is because the correct way to set these things is to pass environment
 | 
				
			||||||
 | 
						// to the `start` job.
 | 
				
			||||||
 | 
						// FIXME: this helper function should be deprecated in favor of calling
 | 
				
			||||||
 | 
						// `create` and `start` jobs directly.
 | 
				
			||||||
 | 
						return c, hc, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Create a test container, start it, wait for it to complete, destroy it,
 | 
				
			||||||
 | 
					// and return its standard output as a string.
 | 
				
			||||||
 | 
					// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
 | 
				
			||||||
 | 
					// If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
 | 
				
			||||||
 | 
					func runContainer(eng *engine.Engine, r *docker.Runtime, args []string, t *testing.T) (output string, err error) {
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
							if err != nil && t != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						container, hc, err := mkContainer(r, args, t)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer r.Destroy(container)
 | 
				
			||||||
 | 
						stdout, err := container.StdoutPipe()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer stdout.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						job := eng.Job("start", container.ID)
 | 
				
			||||||
 | 
						if err := job.ImportEnv(hc); err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := job.Run(); err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container.Wait()
 | 
				
			||||||
 | 
						data, err := ioutil.ReadAll(stdout)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						output = string(data)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this is duplicated from graph_test.go in the docker package.
 | 
				
			||||||
 | 
					func fakeTar() (io.Reader, error) {
 | 
				
			||||||
 | 
						content := []byte("Hello world!\n")
 | 
				
			||||||
 | 
						buf := new(bytes.Buffer)
 | 
				
			||||||
 | 
						tw := tar.NewWriter(buf)
 | 
				
			||||||
 | 
						for _, name := range []string{"/etc/postgres/postgres.conf", "/etc/passwd", "/var/log/postgres/postgres.conf"} {
 | 
				
			||||||
 | 
							hdr := new(tar.Header)
 | 
				
			||||||
 | 
							hdr.Size = int64(len(content))
 | 
				
			||||||
 | 
							hdr.Name = name
 | 
				
			||||||
 | 
							if err := tw.WriteHeader(hdr); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							tw.Write([]byte(content))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tw.Close()
 | 
				
			||||||
 | 
						return buf, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
package iptables
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestIptables(t *testing.T) {
 | 
					 | 
				
			||||||
	if _, err := Raw("-L"); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	path := os.Getenv("PATH")
 | 
					 | 
				
			||||||
	os.Setenv("PATH", "")
 | 
					 | 
				
			||||||
	defer os.Setenv("PATH", path)
 | 
					 | 
				
			||||||
	if _, err := Raw("-L"); err == nil {
 | 
					 | 
				
			||||||
		t.Fatal("Not finding iptables in the PATH should cause an error")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,7 @@ lxc.aa_profile = unconfined
 | 
				
			||||||
#  (Note: 'lxc.cap.keep' is coming soon and should replace this under the
 | 
					#  (Note: 'lxc.cap.keep' is coming soon and should replace this under the
 | 
				
			||||||
#         security principle 'deny all unless explicitly permitted', see
 | 
					#         security principle 'deny all unless explicitly permitted', see
 | 
				
			||||||
#         http://sourceforge.net/mailarchive/message.php?msg_id=31054627 )
 | 
					#         http://sourceforge.net/mailarchive/message.php?msg_id=31054627 )
 | 
				
			||||||
lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod setpcap sys_admin sys_boot sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config
 | 
					lxc.cap.drop = audit_control audit_write mac_admin mac_override mknod setpcap sys_admin sys_module sys_nice sys_pacct sys_rawio sys_resource sys_time sys_tty_config
 | 
				
			||||||
{{end}}
 | 
					{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# limits
 | 
					# limits
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										102
									
								
								lxc_template_unit_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								lxc_template_unit_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLXCConfig(t *testing.T) {
 | 
				
			||||||
 | 
						root, err := ioutil.TempDir("", "TestLXCConfig")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(root)
 | 
				
			||||||
 | 
						// Memory is allocated randomly for testing
 | 
				
			||||||
 | 
						rand.Seed(time.Now().UTC().UnixNano())
 | 
				
			||||||
 | 
						memMin := 33554432
 | 
				
			||||||
 | 
						memMax := 536870912
 | 
				
			||||||
 | 
						mem := memMin + rand.Intn(memMax-memMin)
 | 
				
			||||||
 | 
						// CPU shares as well
 | 
				
			||||||
 | 
						cpuMin := 100
 | 
				
			||||||
 | 
						cpuMax := 10000
 | 
				
			||||||
 | 
						cpu := cpuMin + rand.Intn(cpuMax-cpuMin)
 | 
				
			||||||
 | 
						container := &Container{
 | 
				
			||||||
 | 
							root: root,
 | 
				
			||||||
 | 
							Config: &Config{
 | 
				
			||||||
 | 
								Hostname:        "foobar",
 | 
				
			||||||
 | 
								Memory:          int64(mem),
 | 
				
			||||||
 | 
								CpuShares:       int64(cpu),
 | 
				
			||||||
 | 
								NetworkDisabled: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							hostConfig: &HostConfig{
 | 
				
			||||||
 | 
								Privileged: false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := container.generateLXCConfig(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						grepFile(t, container.lxcConfigPath(), "lxc.utsname = foobar")
 | 
				
			||||||
 | 
						grepFile(t, container.lxcConfigPath(),
 | 
				
			||||||
 | 
							fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
 | 
				
			||||||
 | 
						grepFile(t, container.lxcConfigPath(),
 | 
				
			||||||
 | 
							fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCustomLxcConfig(t *testing.T) {
 | 
				
			||||||
 | 
						root, err := ioutil.TempDir("", "TestCustomLxcConfig")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(root)
 | 
				
			||||||
 | 
						container := &Container{
 | 
				
			||||||
 | 
							root: root,
 | 
				
			||||||
 | 
							Config: &Config{
 | 
				
			||||||
 | 
								Hostname:        "foobar",
 | 
				
			||||||
 | 
								NetworkDisabled: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							hostConfig: &HostConfig{
 | 
				
			||||||
 | 
								Privileged: false,
 | 
				
			||||||
 | 
								LxcConf: []KeyValuePair{
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Key:   "lxc.utsname",
 | 
				
			||||||
 | 
										Value: "docker",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Key:   "lxc.cgroup.cpuset.cpus",
 | 
				
			||||||
 | 
										Value: "0,1",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := container.generateLXCConfig(); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						grepFile(t, container.lxcConfigPath(), "lxc.utsname = docker")
 | 
				
			||||||
 | 
						grepFile(t, container.lxcConfigPath(), "lxc.cgroup.cpuset.cpus = 0,1")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func grepFile(t *testing.T, path string, pattern string) {
 | 
				
			||||||
 | 
						f, err := os.Open(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer f.Close()
 | 
				
			||||||
 | 
						r := bufio.NewReader(f)
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
 | 
							line string
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						err = nil
 | 
				
			||||||
 | 
						for err == nil {
 | 
				
			||||||
 | 
							line, err = r.ReadString('\n')
 | 
				
			||||||
 | 
							if strings.Contains(line, pattern) == true {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								runtime.go
									
										
									
									
									
								
							
							
						
						
									
										38
									
								
								runtime.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
package docker
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	_ "code.google.com/p/gosqlite/sqlite3"
 | 
						_ "code.google.com/p/gosqlite/sqlite3" // registers sqlite
 | 
				
			||||||
	"container/list"
 | 
						"container/list"
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@ import (
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -417,7 +418,8 @@ func (runtime *Runtime) Create(config *Config, name string) (*Container, []strin
 | 
				
			||||||
	// Set the enitity in the graph using the default name specified
 | 
						// Set the enitity in the graph using the default name specified
 | 
				
			||||||
	if _, err := runtime.containerGraph.Set(name, id); err != nil {
 | 
						if _, err := runtime.containerGraph.Set(name, id); err != nil {
 | 
				
			||||||
		if strings.HasSuffix(err.Error(), "name are not unique") {
 | 
							if strings.HasSuffix(err.Error(), "name are not unique") {
 | 
				
			||||||
			return nil, nil, fmt.Errorf("Conflict, %s already exists.", name)
 | 
								conflictingContainer, _ := runtime.GetByName(name)
 | 
				
			||||||
 | 
								return nil, nil, fmt.Errorf("Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", name, utils.TruncateID(conflictingContainer.ID), name)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil, nil, err
 | 
							return nil, nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -548,7 +550,12 @@ func (runtime *Runtime) Commit(container *Container, repository, tag, comment, a
 | 
				
			||||||
	return img, nil
 | 
						return img, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this is deprecated by the getFullName *function*
 | 
				
			||||||
func (runtime *Runtime) getFullName(name string) (string, error) {
 | 
					func (runtime *Runtime) getFullName(name string) (string, error) {
 | 
				
			||||||
 | 
						return getFullName(name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getFullName(name string) (string, error) {
 | 
				
			||||||
	if name == "" {
 | 
						if name == "" {
 | 
				
			||||||
		return "", fmt.Errorf("Container name cannot be empty")
 | 
							return "", fmt.Errorf("Container name cannot be empty")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -762,6 +769,25 @@ func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) {
 | 
				
			||||||
	return archive.ExportChanges(cDir, changes)
 | 
						return archive.ExportChanges(cDir, changes)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Nuke kills all containers then removes all content
 | 
				
			||||||
 | 
					// from the content root, including images, volumes and
 | 
				
			||||||
 | 
					// container filesystems.
 | 
				
			||||||
 | 
					// Again: this will remove your entire docker runtime!
 | 
				
			||||||
 | 
					func (runtime *Runtime) Nuke() error {
 | 
				
			||||||
 | 
						var wg sync.WaitGroup
 | 
				
			||||||
 | 
						for _, container := range runtime.List() {
 | 
				
			||||||
 | 
							wg.Add(1)
 | 
				
			||||||
 | 
							go func(c *Container) {
 | 
				
			||||||
 | 
								c.Kill()
 | 
				
			||||||
 | 
								wg.Done()
 | 
				
			||||||
 | 
							}(container)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
 | 
						runtime.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return os.RemoveAll(runtime.config.Root)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func linkLxcStart(root string) error {
 | 
					func linkLxcStart(root string) error {
 | 
				
			||||||
	sourcePath, err := exec.LookPath("lxc-start")
 | 
						sourcePath, err := exec.LookPath("lxc-start")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -779,6 +805,14 @@ func linkLxcStart(root string) error {
 | 
				
			||||||
	return os.Symlink(sourcePath, targetPath)
 | 
						return os.Symlink(sourcePath, targetPath)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this is a convenience function for integration tests
 | 
				
			||||||
 | 
					// which need direct access to runtime.graph.
 | 
				
			||||||
 | 
					// Once the tests switch to using engine and jobs, this method
 | 
				
			||||||
 | 
					// can go away.
 | 
				
			||||||
 | 
					func (runtime *Runtime) Graph() *Graph {
 | 
				
			||||||
 | 
						return runtime.graph
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// History is a convenience type for storing a list of containers,
 | 
					// History is a convenience type for storing a list of containers,
 | 
				
			||||||
// ordered by creation date.
 | 
					// ordered by creation date.
 | 
				
			||||||
type History []*Container
 | 
					type History []*Container
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										32
									
								
								server.go
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								server.go
									
										
									
									
									
								
							| 
						 | 
					@ -62,6 +62,8 @@ func jobInitApi(job *engine.Job) string {
 | 
				
			||||||
		os.Exit(0)
 | 
							os.Exit(0)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
 | 
						job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
 | 
				
			||||||
 | 
						job.Eng.Hack_SetGlobalVar("httpapi.runtime", srv.runtime)
 | 
				
			||||||
 | 
						job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", srv.runtime.networkManager.bridgeNetwork.IP)
 | 
				
			||||||
	if err := job.Eng.Register("create", srv.ContainerCreate); err != nil {
 | 
						if err := job.Eng.Register("create", srv.ContainerCreate); err != nil {
 | 
				
			||||||
		return err.Error()
 | 
							return err.Error()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -422,9 +424,9 @@ func (srv *Server) ImageHistory(name string) ([]APIHistory, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (srv *Server) ContainerTop(name, ps_args string) (*APITop, error) {
 | 
					func (srv *Server) ContainerTop(name, psArgs string) (*APITop, error) {
 | 
				
			||||||
	if container := srv.runtime.Get(name); container != nil {
 | 
						if container := srv.runtime.Get(name); container != nil {
 | 
				
			||||||
		output, err := exec.Command("lxc-ps", "--name", container.ID, "--", ps_args).CombinedOutput()
 | 
							output, err := exec.Command("lxc-ps", "--name", container.ID, "--", psArgs).CombinedOutput()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("lxc-ps: %s (%s)", err, output)
 | 
								return nil, fmt.Errorf("lxc-ps: %s (%s)", err, output)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -532,6 +534,7 @@ func (srv *Server) ContainerCommit(name, repo, tag, author, comment string, conf
 | 
				
			||||||
	return img.ID, err
 | 
						return img.ID, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this should be called ImageTag
 | 
				
			||||||
func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
 | 
					func (srv *Server) ContainerTag(name, repo, tag string, force bool) error {
 | 
				
			||||||
	if err := srv.runtime.repositories.Set(repo, tag, name, force); err != nil {
 | 
						if err := srv.runtime.repositories.Set(repo, tag, name, force); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
| 
						 | 
					@ -891,12 +894,13 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, localName
 | 
				
			||||||
					out.Write(sf.FormatStatus("", "Image %s already pushed, skipping", elem.ID))
 | 
										out.Write(sf.FormatStatus("", "Image %s already pushed, skipping", elem.ID))
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if checksum, err := srv.pushImage(r, out, remoteName, elem.ID, ep, repoData.Tokens, sf); err != nil {
 | 
									checksum, err := srv.pushImage(r, out, remoteName, elem.ID, ep, repoData.Tokens, sf)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
					// FIXME: Continue on error?
 | 
										// FIXME: Continue on error?
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					elem.Checksum = checksum
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
									elem.Checksum = checksum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if err := pushTags(); err != nil {
 | 
									if err := pushTags(); err != nil {
 | 
				
			||||||
					return err
 | 
										return err
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -936,13 +940,15 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgID,
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", fmt.Errorf("Failed to generate layer archive: %s", err)
 | 
							return "", fmt.Errorf("Failed to generate layer archive: %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(layerData.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Send the layer
 | 
						// Send the layer
 | 
				
			||||||
	if checksum, err := r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("", "Pushing", "%8v/%v (%v)"), sf, false), ep, token, jsonRaw); err != nil {
 | 
						checksum, err = r.PushImageLayerRegistry(imgData.ID, utils.ProgressReader(layerData, int(layerData.Size), out, sf.FormatProgress("", "Pushing", "%8v/%v (%v)"), sf, false), ep, token, jsonRaw)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		imgData.Checksum = checksum
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						imgData.Checksum = checksum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	out.Write(sf.FormatStatus("", ""))
 | 
						out.Write(sf.FormatStatus("", ""))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Send the checksum
 | 
						// Send the checksum
 | 
				
			||||||
| 
						 | 
					@ -1065,7 +1071,12 @@ func (srv *Server) ContainerCreate(job *engine.Job) string {
 | 
				
			||||||
		return err.Error()
 | 
							return err.Error()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
 | 
						srv.LogEvent("create", container.ID, srv.runtime.repositories.ImageName(container.Image))
 | 
				
			||||||
	job.Printf("%s\n", container.ID)
 | 
						// FIXME: this is necessary because runtime.Create might return a nil container
 | 
				
			||||||
 | 
						// with a non-nil error. This should not happen! Once it's fixed we
 | 
				
			||||||
 | 
						// can remove this workaround.
 | 
				
			||||||
 | 
						if container != nil {
 | 
				
			||||||
 | 
							job.Printf("%s\n", container.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	for _, warning := range buildWarnings {
 | 
						for _, warning := range buildWarnings {
 | 
				
			||||||
		job.Errorf("%s\n", warning)
 | 
							job.Errorf("%s\n", warning)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1603,7 +1614,7 @@ func (srv *Server) HTTPRequestFactory(metaHeaders map[string][]string) *utils.HT
 | 
				
			||||||
	return srv.reqFactory
 | 
						return srv.reqFactory
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (srv *Server) LogEvent(action, id, from string) {
 | 
					func (srv *Server) LogEvent(action, id, from string) *utils.JSONMessage {
 | 
				
			||||||
	now := time.Now().Unix()
 | 
						now := time.Now().Unix()
 | 
				
			||||||
	jm := utils.JSONMessage{Status: action, ID: id, From: from, Time: now}
 | 
						jm := utils.JSONMessage{Status: action, ID: id, From: from, Time: now}
 | 
				
			||||||
	srv.events = append(srv.events, jm)
 | 
						srv.events = append(srv.events, jm)
 | 
				
			||||||
| 
						 | 
					@ -1613,6 +1624,7 @@ func (srv *Server) LogEvent(action, id, from string) {
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						return &jm
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Server struct {
 | 
					type Server struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										109
									
								
								server_unit_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								server_unit_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,109 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPools(t *testing.T) {
 | 
				
			||||||
 | 
						srv := &Server{
 | 
				
			||||||
 | 
							pullingPool: make(map[string]struct{}),
 | 
				
			||||||
 | 
							pushingPool: make(map[string]struct{}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := srv.poolAdd("pull", "test1")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolAdd("pull", "test2")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolAdd("push", "test1")
 | 
				
			||||||
 | 
						if err == nil || err.Error() != "pull test1 is already in progress" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected `pull test1 is already in progress`")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolAdd("pull", "test1")
 | 
				
			||||||
 | 
						if err == nil || err.Error() != "pull test1 is already in progress" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected `pull test1 is already in progress`")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolAdd("wait", "test3")
 | 
				
			||||||
 | 
						if err == nil || err.Error() != "Unknown pool type" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected `Unknown pool type`")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = srv.poolRemove("pull", "test2")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolRemove("pull", "test2")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolRemove("pull", "test1")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolRemove("push", "test1")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = srv.poolRemove("wait", "test3")
 | 
				
			||||||
 | 
						if err == nil || err.Error() != "Unknown pool type" {
 | 
				
			||||||
 | 
							t.Fatalf("Expected `Unknown pool type`")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLogEvent(t *testing.T) {
 | 
				
			||||||
 | 
						srv := &Server{
 | 
				
			||||||
 | 
							events:    make([]utils.JSONMessage, 0, 64),
 | 
				
			||||||
 | 
							listeners: make(map[string]chan utils.JSONMessage),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv.LogEvent("fakeaction", "fakeid", "fakeimage")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						listener := make(chan utils.JSONMessage)
 | 
				
			||||||
 | 
						srv.Lock()
 | 
				
			||||||
 | 
						srv.listeners["test"] = listener
 | 
				
			||||||
 | 
						srv.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv.LogEvent("fakeaction2", "fakeid", "fakeimage")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(srv.events) != 2 {
 | 
				
			||||||
 | 
							t.Fatalf("Expected 2 events, found %d", len(srv.events))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							time.Sleep(200 * time.Millisecond)
 | 
				
			||||||
 | 
							srv.LogEvent("fakeaction3", "fakeid", "fakeimage")
 | 
				
			||||||
 | 
							time.Sleep(200 * time.Millisecond)
 | 
				
			||||||
 | 
							srv.LogEvent("fakeaction4", "fakeid", "fakeimage")
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setTimeout(t, "Listening for events timed out", 2*time.Second, func() {
 | 
				
			||||||
 | 
							for i := 2; i < 4; i++ {
 | 
				
			||||||
 | 
								event := <-listener
 | 
				
			||||||
 | 
								if event != srv.events[i] {
 | 
				
			||||||
 | 
									t.Fatalf("Event received it different than expected")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: this is duplicated from integration/commands_test.go
 | 
				
			||||||
 | 
					func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
 | 
				
			||||||
 | 
						c := make(chan bool)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make sure we are not too long
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							time.Sleep(d)
 | 
				
			||||||
 | 
							c <- true
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							f()
 | 
				
			||||||
 | 
							c <- false
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
						if <-c && msg != "" {
 | 
				
			||||||
 | 
							t.Fatal(msg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										111
									
								
								sorter_test.go
									
										
									
									
									
								
							
							
						
						
									
										111
									
								
								sorter_test.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,111 +0,0 @@
 | 
				
			||||||
package docker
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestServerListOrderedImagesByCreationDate(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	archive, err := fakeTar()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, err = runtime.graph.Create(archive, nil, "Testing", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	images, err := srv.Images(true, "")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if images[0].Created < images[1].Created {
 | 
					 | 
				
			||||||
		t.Error("Expected []APIImges to be ordered by most recent creation date.")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestServerListOrderedImagesByCreationDateAndTag(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := generateImage("bar", runtime)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	time.Sleep(time.Second)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = generateImage("zed", runtime)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
					 | 
				
			||||||
	images, err := srv.Images(true, "")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if images[0].RepoTags[0] != "repo:zed" && images[0].RepoTags[0] != "repo:bar" {
 | 
					 | 
				
			||||||
		t.Errorf("Expected []APIImges to be ordered by most recent creation date. %s", images)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func generateImage(name string, runtime *Runtime) error {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	archive, err := fakeTar()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	image, err := runtime.graph.Create(archive, nil, "Testing", "", nil)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	srv := &Server{runtime: runtime}
 | 
					 | 
				
			||||||
	srv.ContainerTag(image.ID, "repo", name, false)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestSortUniquePorts(t *testing.T) {
 | 
					 | 
				
			||||||
	ports := []Port{
 | 
					 | 
				
			||||||
		Port("6379/tcp"),
 | 
					 | 
				
			||||||
		Port("22/tcp"),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sortPorts(ports, func(ip, jp Port) bool {
 | 
					 | 
				
			||||||
		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	first := ports[0]
 | 
					 | 
				
			||||||
	if fmt.Sprint(first) != "22/tcp" {
 | 
					 | 
				
			||||||
		t.Log(fmt.Sprint(first))
 | 
					 | 
				
			||||||
		t.Fail()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestSortSamePortWithDifferentProto(t *testing.T) {
 | 
					 | 
				
			||||||
	ports := []Port{
 | 
					 | 
				
			||||||
		Port("8888/tcp"),
 | 
					 | 
				
			||||||
		Port("8888/udp"),
 | 
					 | 
				
			||||||
		Port("6379/tcp"),
 | 
					 | 
				
			||||||
		Port("6379/udp"),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sortPorts(ports, func(ip, jp Port) bool {
 | 
					 | 
				
			||||||
		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	first := ports[0]
 | 
					 | 
				
			||||||
	if fmt.Sprint(first) != "6379/tcp" {
 | 
					 | 
				
			||||||
		t.Fail()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										41
									
								
								sorter_unit_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								sorter_unit_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSortUniquePorts(t *testing.T) {
 | 
				
			||||||
 | 
						ports := []Port{
 | 
				
			||||||
 | 
							Port("6379/tcp"),
 | 
				
			||||||
 | 
							Port("22/tcp"),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sortPorts(ports, func(ip, jp Port) bool {
 | 
				
			||||||
 | 
							return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						first := ports[0]
 | 
				
			||||||
 | 
						if fmt.Sprint(first) != "22/tcp" {
 | 
				
			||||||
 | 
							t.Log(fmt.Sprint(first))
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSortSamePortWithDifferentProto(t *testing.T) {
 | 
				
			||||||
 | 
						ports := []Port{
 | 
				
			||||||
 | 
							Port("8888/tcp"),
 | 
				
			||||||
 | 
							Port("8888/udp"),
 | 
				
			||||||
 | 
							Port("6379/tcp"),
 | 
				
			||||||
 | 
							Port("6379/udp"),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sortPorts(ports, func(ip, jp Port) bool {
 | 
				
			||||||
 | 
							return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						first := ports[0]
 | 
				
			||||||
 | 
						if fmt.Sprint(first) != "6379/tcp" {
 | 
				
			||||||
 | 
							t.Fail()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								tags_test.go
									
										
									
									
									
								
							
							
						
						
									
										46
									
								
								tags_test.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,46 +0,0 @@
 | 
				
			||||||
package docker
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLookupImage(t *testing.T) {
 | 
					 | 
				
			||||||
	runtime := mkRuntime(t)
 | 
					 | 
				
			||||||
	defer nuke(runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	} else if img == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 1 image, none found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageName + ":" + DEFAULTTAG); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	} else if img == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 1 image, none found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageName + ":" + "fail"); err == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected error, none found")
 | 
					 | 
				
			||||||
	} else if img != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 0 image, 1 found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage("fail:fail"); err == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected error, none found")
 | 
					 | 
				
			||||||
	} else if img != nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 0 image, 1 found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageID); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	} else if img == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 1 image, none found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if img, err := runtime.repositories.LookupImage(unitTestImageName + ":" + unitTestImageID); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	} else if img == nil {
 | 
					 | 
				
			||||||
		t.Errorf("Expected 1 image, none found")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										85
									
								
								tags_unit_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tags_unit_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					package docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/graphdriver"
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/utils"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						testImageName = "myapp"
 | 
				
			||||||
 | 
						testImageID   = "foo"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func mkTestTagStore(root string, t *testing.T) *TagStore {
 | 
				
			||||||
 | 
						driver, err := graphdriver.New(root)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						graph, err := NewGraph(root, driver)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						store, err := NewTagStore(path.Join(root, "tags"), graph)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						archive, err := fakeTar()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						img := &Image{ID: testImageID}
 | 
				
			||||||
 | 
						if err := graph.Register(nil, archive, img); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := store.Set(testImageName, "", testImageID, false); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return store
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLookupImage(t *testing.T) {
 | 
				
			||||||
 | 
						tmp, err := utils.TestDirectory("")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer os.RemoveAll(tmp)
 | 
				
			||||||
 | 
						store := mkTestTagStore(tmp, t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if img, err := store.LookupImage(testImageName); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						} else if img == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 1 image, none found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if img, err := store.LookupImage(testImageName + ":" + DEFAULTTAG); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						} else if img == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 1 image, none found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if img, err := store.LookupImage(testImageName + ":" + "fail"); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected error, none found")
 | 
				
			||||||
 | 
						} else if img != nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 0 image, 1 found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if img, err := store.LookupImage("fail:fail"); err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected error, none found")
 | 
				
			||||||
 | 
						} else if img != nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 0 image, 1 found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if img, err := store.LookupImage(testImageID); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						} else if img == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 1 image, none found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if img, err := store.LookupImage(testImageName + ":" + testImageID); err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						} else if img == nil {
 | 
				
			||||||
 | 
							t.Errorf("Expected 1 image, none found")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -81,12 +81,12 @@ func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator {
 | 
				
			||||||
	return ret
 | 
						return ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
 | 
					func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
 | 
				
			||||||
	if req == nil {
 | 
						if req == nil {
 | 
				
			||||||
		return req, nil
 | 
							return req, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	userAgent := appendVersions(req.UserAgent(), self.versions...)
 | 
						userAgent := appendVersions(req.UserAgent(), h.versions...)
 | 
				
			||||||
	if len(userAgent) > 0 {
 | 
						if len(userAgent) > 0 {
 | 
				
			||||||
		req.Header.Set("User-Agent", userAgent)
 | 
							req.Header.Set("User-Agent", userAgent)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -97,11 +97,11 @@ type HTTPMetaHeadersDecorator struct {
 | 
				
			||||||
	Headers map[string][]string
 | 
						Headers map[string][]string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
 | 
					func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
 | 
				
			||||||
	if self.Headers == nil {
 | 
						if h.Headers == nil {
 | 
				
			||||||
		return req, nil
 | 
							return req, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for k, v := range self.Headers {
 | 
						for k, v := range h.Headers {
 | 
				
			||||||
		req.Header[k] = v
 | 
							req.Header[k] = v
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return req, nil
 | 
						return req, nil
 | 
				
			||||||
| 
						 | 
					@ -114,25 +114,25 @@ type HTTPRequestFactory struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
 | 
					func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
 | 
				
			||||||
	ret := new(HTTPRequestFactory)
 | 
						return &HTTPRequestFactory{
 | 
				
			||||||
	ret.decorators = d
 | 
							decorators: d,
 | 
				
			||||||
	return ret
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewRequest() creates a new *http.Request,
 | 
					// NewRequest() creates a new *http.Request,
 | 
				
			||||||
// applies all decorators in the HTTPRequestFactory on the request,
 | 
					// applies all decorators in the HTTPRequestFactory on the request,
 | 
				
			||||||
// then applies decorators provided by d on the request.
 | 
					// then applies decorators provided by d on the request.
 | 
				
			||||||
func (self *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
 | 
					func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
 | 
				
			||||||
	req, err := http.NewRequest(method, urlStr, body)
 | 
						req, err := http.NewRequest(method, urlStr, body)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// By default, a nil factory should work.
 | 
						// By default, a nil factory should work.
 | 
				
			||||||
	if self == nil {
 | 
						if h == nil {
 | 
				
			||||||
		return req, nil
 | 
							return req, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, dec := range self.decorators {
 | 
						for _, dec := range h.decorators {
 | 
				
			||||||
		req, err = dec.ChangeRequest(req)
 | 
							req, err = dec.ChangeRequest(req)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1123,7 +1123,7 @@ func (graph *DependencyGraph) GenerateTraversalMap() ([][]string, error) {
 | 
				
			||||||
	for len(processed) < len(graph.nodes) {
 | 
						for len(processed) < len(graph.nodes) {
 | 
				
			||||||
		// Use a temporary buffer for processed nodes, otherwise
 | 
							// Use a temporary buffer for processed nodes, otherwise
 | 
				
			||||||
		// nodes that depend on each other could end up in the same round.
 | 
							// nodes that depend on each other could end up in the same round.
 | 
				
			||||||
		tmp_processed := []*DependencyNode{}
 | 
							tmpProcessed := []*DependencyNode{}
 | 
				
			||||||
		for _, node := range graph.nodes {
 | 
							for _, node := range graph.nodes {
 | 
				
			||||||
			// If the node has more dependencies than what we have cleared,
 | 
								// If the node has more dependencies than what we have cleared,
 | 
				
			||||||
			// it won't be valid for this round.
 | 
								// it won't be valid for this round.
 | 
				
			||||||
| 
						 | 
					@ -1137,7 +1137,7 @@ func (graph *DependencyGraph) GenerateTraversalMap() ([][]string, error) {
 | 
				
			||||||
			// It's not been processed yet and has 0 deps. Add it!
 | 
								// It's not been processed yet and has 0 deps. Add it!
 | 
				
			||||||
			// (this is a shortcut for what we're doing below)
 | 
								// (this is a shortcut for what we're doing below)
 | 
				
			||||||
			if node.Degree() == 0 {
 | 
								if node.Degree() == 0 {
 | 
				
			||||||
				tmp_processed = append(tmp_processed, node)
 | 
									tmpProcessed = append(tmpProcessed, node)
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// If at least one dep hasn't been processed yet, we can't
 | 
								// If at least one dep hasn't been processed yet, we can't
 | 
				
			||||||
| 
						 | 
					@ -1151,17 +1151,17 @@ func (graph *DependencyGraph) GenerateTraversalMap() ([][]string, error) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			// All deps have already been processed. Add it!
 | 
								// All deps have already been processed. Add it!
 | 
				
			||||||
			if ok {
 | 
								if ok {
 | 
				
			||||||
				tmp_processed = append(tmp_processed, node)
 | 
									tmpProcessed = append(tmpProcessed, node)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		Debugf("Round %d: found %d available nodes", len(result), len(tmp_processed))
 | 
							Debugf("Round %d: found %d available nodes", len(result), len(tmpProcessed))
 | 
				
			||||||
		// If no progress has been made this round,
 | 
							// If no progress has been made this round,
 | 
				
			||||||
		// that means we have circular dependencies.
 | 
							// that means we have circular dependencies.
 | 
				
			||||||
		if len(tmp_processed) == 0 {
 | 
							if len(tmpProcessed) == 0 {
 | 
				
			||||||
			return nil, fmt.Errorf("Could not find a solution to this dependency graph")
 | 
								return nil, fmt.Errorf("Could not find a solution to this dependency graph")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		round := []string{}
 | 
							round := []string{}
 | 
				
			||||||
		for _, nd := range tmp_processed {
 | 
							for _, nd := range tmpProcessed {
 | 
				
			||||||
			round = append(round, nd.id)
 | 
								round = append(round, nd.id)
 | 
				
			||||||
			processed[nd] = true
 | 
								processed[nd] = true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1242,3 +1242,40 @@ func PartParser(template, data string) (map[string]string, error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return out, nil
 | 
						return out, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var globalTestID string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TestDirectory creates a new temporary directory and returns its path.
 | 
				
			||||||
 | 
					// The contents of directory at path `templateDir` is copied into the
 | 
				
			||||||
 | 
					// new directory.
 | 
				
			||||||
 | 
					func TestDirectory(templateDir string) (dir string, err error) {
 | 
				
			||||||
 | 
						if globalTestID == "" {
 | 
				
			||||||
 | 
							globalTestID = RandomString()[:4]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2))
 | 
				
			||||||
 | 
						if prefix == "" {
 | 
				
			||||||
 | 
							prefix = "docker-test-"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dir, err = ioutil.TempDir("", prefix)
 | 
				
			||||||
 | 
						if err = os.Remove(dir); err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if templateDir != "" {
 | 
				
			||||||
 | 
							if err = CopyDirectory(templateDir, dir); err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetCallerName introspects the call stack and returns the name of the
 | 
				
			||||||
 | 
					// function `depth` levels down in the stack.
 | 
				
			||||||
 | 
					func GetCallerName(depth int) string {
 | 
				
			||||||
 | 
						// Use the caller function name as a prefix.
 | 
				
			||||||
 | 
						// This helps trace temp directories back to their test.
 | 
				
			||||||
 | 
						pc, _, _, _ := runtime.Caller(depth + 1)
 | 
				
			||||||
 | 
						callerLongName := runtime.FuncForPC(pc).Name()
 | 
				
			||||||
 | 
						parts := strings.Split(callerLongName, ".")
 | 
				
			||||||
 | 
						callerShortName := parts[len(parts)-1]
 | 
				
			||||||
 | 
						return callerShortName
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										493
									
								
								utils_test.go
									
										
									
									
									
								
							
							
						
						
									
										493
									
								
								utils_test.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,493 +0,0 @@
 | 
				
			||||||
package docker
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"github.com/dotcloud/docker/engine"
 | 
					 | 
				
			||||||
	"github.com/dotcloud/docker/utils"
 | 
					 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
	"path"
 | 
					 | 
				
			||||||
	"runtime"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// This file contains utility functions for docker's unit test suite.
 | 
					 | 
				
			||||||
// It has to be named XXX_test.go, apparently, in other to access private functions
 | 
					 | 
				
			||||||
// from other XXX_test.go functions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var globalTestID string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Create a temporary runtime suitable for unit testing.
 | 
					 | 
				
			||||||
// Call t.Fatal() at the first error.
 | 
					 | 
				
			||||||
func mkRuntime(f utils.Fataler) *Runtime {
 | 
					 | 
				
			||||||
	root, err := newTestDirectory(unitTestStoreBase)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		f.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config := &DaemonConfig{
 | 
					 | 
				
			||||||
		Root:        root,
 | 
					 | 
				
			||||||
		AutoRestart: false,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	r, err := NewRuntimeFromDirectory(config)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		f.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	r.UpdateCapabilities(true)
 | 
					 | 
				
			||||||
	return r
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createNamedTestContainer(eng *engine.Engine, config *Config, f utils.Fataler, name string) (shortId string) {
 | 
					 | 
				
			||||||
	job := eng.Job("create", name)
 | 
					 | 
				
			||||||
	if err := job.ImportEnv(config); err != nil {
 | 
					 | 
				
			||||||
		f.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	job.StdoutParseString(&shortId)
 | 
					 | 
				
			||||||
	if err := job.Run(); err != nil {
 | 
					 | 
				
			||||||
		f.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func createTestContainer(eng *engine.Engine, config *Config, f utils.Fataler) (shortId string) {
 | 
					 | 
				
			||||||
	return createNamedTestContainer(eng, config, f, "")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func mkServerFromEngine(eng *engine.Engine, t utils.Fataler) *Server {
 | 
					 | 
				
			||||||
	iSrv := eng.Hack_GetGlobalVar("httpapi.server")
 | 
					 | 
				
			||||||
	if iSrv == nil {
 | 
					 | 
				
			||||||
		panic("Legacy server field not set in engine")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	srv, ok := iSrv.(*Server)
 | 
					 | 
				
			||||||
	if !ok {
 | 
					 | 
				
			||||||
		panic("Legacy server field in engine does not cast to *Server")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return srv
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewTestEngine(t utils.Fataler) *engine.Engine {
 | 
					 | 
				
			||||||
	root, err := newTestDirectory(unitTestStoreBase)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	eng, err := engine.New(root)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Load default plugins
 | 
					 | 
				
			||||||
	// (This is manually copied and modified from main() until we have a more generic plugin system)
 | 
					 | 
				
			||||||
	job := eng.Job("initapi")
 | 
					 | 
				
			||||||
	job.Setenv("Root", root)
 | 
					 | 
				
			||||||
	job.SetenvBool("AutoRestart", false)
 | 
					 | 
				
			||||||
	if err := job.Run(); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return eng
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newTestDirectory(templateDir string) (dir string, err error) {
 | 
					 | 
				
			||||||
	if globalTestID == "" {
 | 
					 | 
				
			||||||
		globalTestID = GenerateID()[:4]
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, getCallerName(2))
 | 
					 | 
				
			||||||
	if prefix == "" {
 | 
					 | 
				
			||||||
		prefix = "docker-test-"
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	dir, err = ioutil.TempDir("", prefix)
 | 
					 | 
				
			||||||
	if err = os.Remove(dir); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err = utils.CopyDirectory(templateDir, dir); err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func getCallerName(depth int) string {
 | 
					 | 
				
			||||||
	// Use the caller function name as a prefix.
 | 
					 | 
				
			||||||
	// This helps trace temp directories back to their test.
 | 
					 | 
				
			||||||
	pc, _, _, _ := runtime.Caller(depth + 1)
 | 
					 | 
				
			||||||
	callerLongName := runtime.FuncForPC(pc).Name()
 | 
					 | 
				
			||||||
	parts := strings.Split(callerLongName, ".")
 | 
					 | 
				
			||||||
	callerShortName := parts[len(parts)-1]
 | 
					 | 
				
			||||||
	return callerShortName
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Write `content` to the file at path `dst`, creating it if necessary,
 | 
					 | 
				
			||||||
// as well as any missing directories.
 | 
					 | 
				
			||||||
// The file is truncated if it already exists.
 | 
					 | 
				
			||||||
// Call t.Fatal() at the first error.
 | 
					 | 
				
			||||||
func writeFile(dst, content string, t *testing.T) {
 | 
					 | 
				
			||||||
	// Create subdirectories if necessary
 | 
					 | 
				
			||||||
	if err := os.MkdirAll(path.Dir(dst), 0700); err != nil && !os.IsExist(err) {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0700)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// Write content (truncate if it exists)
 | 
					 | 
				
			||||||
	if _, err := io.Copy(f, strings.NewReader(content)); err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Return the contents of file at path `src`.
 | 
					 | 
				
			||||||
// Call t.Fatal() at the first error (including if the file doesn't exist)
 | 
					 | 
				
			||||||
func readFile(src string, t *testing.T) (content string) {
 | 
					 | 
				
			||||||
	f, err := os.Open(src)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	data, err := ioutil.ReadAll(f)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return string(data)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Create a test container from the given runtime `r` and run arguments `args`.
 | 
					 | 
				
			||||||
// If the image name is "_", (eg. []string{"-i", "-t", "_", "bash"}, it is
 | 
					 | 
				
			||||||
// dynamically replaced by the current test image.
 | 
					 | 
				
			||||||
// The caller is responsible for destroying the container.
 | 
					 | 
				
			||||||
// Call t.Fatal() at the first error.
 | 
					 | 
				
			||||||
func mkContainer(r *Runtime, args []string, t *testing.T) (*Container, error) {
 | 
					 | 
				
			||||||
	config, hostConfig, _, err := ParseRun(args, nil)
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if err != nil && t != nil {
 | 
					 | 
				
			||||||
			t.Fatal(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if config.Image == "_" {
 | 
					 | 
				
			||||||
		config.Image = GetTestImage(r).ID
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	c, _, err := r.Create(config, "")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	c.hostConfig = hostConfig
 | 
					 | 
				
			||||||
	return c, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Create a test container, start it, wait for it to complete, destroy it,
 | 
					 | 
				
			||||||
// and return its standard output as a string.
 | 
					 | 
				
			||||||
// The image name (eg. the XXX in []string{"-i", "-t", "XXX", "bash"}, is dynamically replaced by the current test image.
 | 
					 | 
				
			||||||
// If t is not nil, call t.Fatal() at the first error. Otherwise return errors normally.
 | 
					 | 
				
			||||||
func runContainer(r *Runtime, args []string, t *testing.T) (output string, err error) {
 | 
					 | 
				
			||||||
	defer func() {
 | 
					 | 
				
			||||||
		if err != nil && t != nil {
 | 
					 | 
				
			||||||
			t.Fatal(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
	container, err := mkContainer(r, args, t)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer r.Destroy(container)
 | 
					 | 
				
			||||||
	stdout, err := container.StdoutPipe()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer stdout.Close()
 | 
					 | 
				
			||||||
	if err := container.Start(); err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	container.Wait()
 | 
					 | 
				
			||||||
	data, err := ioutil.ReadAll(stdout)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	output = string(data)
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestCompareConfig(t *testing.T) {
 | 
					 | 
				
			||||||
	volumes1 := make(map[string]struct{})
 | 
					 | 
				
			||||||
	volumes1["/test1"] = struct{}{}
 | 
					 | 
				
			||||||
	config1 := Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "11111111",
 | 
					 | 
				
			||||||
		Volumes:     volumes1,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config2 := Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"0.0.0.0", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "11111111",
 | 
					 | 
				
			||||||
		Volumes:     volumes1,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config3 := Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "11111111",
 | 
					 | 
				
			||||||
		Volumes:     volumes1,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	config4 := Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "22222222",
 | 
					 | 
				
			||||||
		Volumes:     volumes1,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	volumes2 := make(map[string]struct{})
 | 
					 | 
				
			||||||
	volumes2["/test2"] = struct{}{}
 | 
					 | 
				
			||||||
	config5 := Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"0000:0000", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "11111111",
 | 
					 | 
				
			||||||
		Volumes:     volumes2,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if CompareConfig(&config1, &config2) {
 | 
					 | 
				
			||||||
		t.Fatalf("CompareConfig should return false, Dns are different")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if CompareConfig(&config1, &config3) {
 | 
					 | 
				
			||||||
		t.Fatalf("CompareConfig should return false, PortSpecs are different")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if CompareConfig(&config1, &config4) {
 | 
					 | 
				
			||||||
		t.Fatalf("CompareConfig should return false, VolumesFrom are different")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if CompareConfig(&config1, &config5) {
 | 
					 | 
				
			||||||
		t.Fatalf("CompareConfig should return false, Volumes are different")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !CompareConfig(&config1, &config1) {
 | 
					 | 
				
			||||||
		t.Fatalf("CompareConfig should return true")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestMergeConfig(t *testing.T) {
 | 
					 | 
				
			||||||
	volumesImage := make(map[string]struct{})
 | 
					 | 
				
			||||||
	volumesImage["/test1"] = struct{}{}
 | 
					 | 
				
			||||||
	volumesImage["/test2"] = struct{}{}
 | 
					 | 
				
			||||||
	configImage := &Config{
 | 
					 | 
				
			||||||
		Dns:         []string{"1.1.1.1", "2.2.2.2"},
 | 
					 | 
				
			||||||
		PortSpecs:   []string{"1111:1111", "2222:2222"},
 | 
					 | 
				
			||||||
		Env:         []string{"VAR1=1", "VAR2=2"},
 | 
					 | 
				
			||||||
		VolumesFrom: "1111",
 | 
					 | 
				
			||||||
		Volumes:     volumesImage,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	volumesUser := make(map[string]struct{})
 | 
					 | 
				
			||||||
	volumesUser["/test3"] = struct{}{}
 | 
					 | 
				
			||||||
	configUser := &Config{
 | 
					 | 
				
			||||||
		Dns:       []string{"3.3.3.3"},
 | 
					 | 
				
			||||||
		PortSpecs: []string{"3333:2222", "3333:3333"},
 | 
					 | 
				
			||||||
		Env:       []string{"VAR2=3", "VAR3=3"},
 | 
					 | 
				
			||||||
		Volumes:   volumesUser,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := MergeConfig(configUser, configImage); err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(configUser.Dns) != 3 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 3 dns, 1.1.1.1, 2.2.2.2 and 3.3.3.3, found %d", len(configUser.Dns))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, dns := range configUser.Dns {
 | 
					 | 
				
			||||||
		if dns != "1.1.1.1" && dns != "2.2.2.2" && dns != "3.3.3.3" {
 | 
					 | 
				
			||||||
			t.Fatalf("Expected 1.1.1.1 or 2.2.2.2 or 3.3.3.3, found %s", dns)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(configUser.ExposedPorts) != 3 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 3 ExposedPorts, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for portSpecs := range configUser.ExposedPorts {
 | 
					 | 
				
			||||||
		if portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
 | 
					 | 
				
			||||||
			t.Fatalf("Expected 1111 or 2222 or 3333, found %s", portSpecs)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(configUser.Env) != 3 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 3 env var, VAR1=1, VAR2=3 and VAR3=3, found %d", len(configUser.Env))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, env := range configUser.Env {
 | 
					 | 
				
			||||||
		if env != "VAR1=1" && env != "VAR2=3" && env != "VAR3=3" {
 | 
					 | 
				
			||||||
			t.Fatalf("Expected VAR1=1 or VAR2=3 or VAR3=3, found %s", env)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(configUser.Volumes) != 3 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for v := range configUser.Volumes {
 | 
					 | 
				
			||||||
		if v != "/test1" && v != "/test2" && v != "/test3" {
 | 
					 | 
				
			||||||
			t.Fatalf("Expected /test1 or /test2 or /test3, found %s", v)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if configUser.VolumesFrom != "1111" {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ports, _, err := parsePortSpecs([]string{"0000"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	configImage2 := &Config{
 | 
					 | 
				
			||||||
		ExposedPorts: ports,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err := MergeConfig(configUser, configImage2); err != nil {
 | 
					 | 
				
			||||||
		t.Error(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(configUser.ExposedPorts) != 4 {
 | 
					 | 
				
			||||||
		t.Fatalf("Expected 4 ExposedPorts, 0000, 1111, 2222 and 3333, found %d", len(configUser.ExposedPorts))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for portSpecs := range configUser.ExposedPorts {
 | 
					 | 
				
			||||||
		if portSpecs.Port() != "0000" && portSpecs.Port() != "1111" && portSpecs.Port() != "2222" && portSpecs.Port() != "3333" {
 | 
					 | 
				
			||||||
			t.Fatalf("Expected 0000 or 1111 or 2222 or 3333, found %s", portSpecs)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestParseLxcConfOpt(t *testing.T) {
 | 
					 | 
				
			||||||
	opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, o := range opts {
 | 
					 | 
				
			||||||
		k, v, err := parseLxcOpt(o)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if k != "lxc.utsname" {
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if v != "docker" {
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
 | 
					 | 
				
			||||||
	ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(ports) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(ports))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(bindings) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(bindings))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for k := range ports {
 | 
					 | 
				
			||||||
		if k.Proto() != "tcp" {
 | 
					 | 
				
			||||||
			t.Logf("Expected tcp got %s", k.Proto())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if k.Port() != "80" {
 | 
					 | 
				
			||||||
			t.Logf("Expected 80 got %s", k.Port())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		b, exists := bindings[k]
 | 
					 | 
				
			||||||
		if !exists {
 | 
					 | 
				
			||||||
			t.Log("Binding does not exist")
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(b) != 1 {
 | 
					 | 
				
			||||||
			t.Logf("Expected 1 got %d", len(b))
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		s := b[0]
 | 
					 | 
				
			||||||
		if s.HostPort != "" {
 | 
					 | 
				
			||||||
			t.Logf("Expected \"\" got %s", s.HostPort)
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if s.HostIp != "192.168.1.100" {
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestParseNetworkOptsPublic(t *testing.T) {
 | 
					 | 
				
			||||||
	ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(ports) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(ports))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(bindings) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(bindings))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for k := range ports {
 | 
					 | 
				
			||||||
		if k.Proto() != "tcp" {
 | 
					 | 
				
			||||||
			t.Logf("Expected tcp got %s", k.Proto())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if k.Port() != "80" {
 | 
					 | 
				
			||||||
			t.Logf("Expected 80 got %s", k.Port())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		b, exists := bindings[k]
 | 
					 | 
				
			||||||
		if !exists {
 | 
					 | 
				
			||||||
			t.Log("Binding does not exist")
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(b) != 1 {
 | 
					 | 
				
			||||||
			t.Logf("Expected 1 got %d", len(b))
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		s := b[0]
 | 
					 | 
				
			||||||
		if s.HostPort != "8080" {
 | 
					 | 
				
			||||||
			t.Logf("Expected 8080 got %s", s.HostPort)
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if s.HostIp != "192.168.1.100" {
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestParseNetworkOptsUdp(t *testing.T) {
 | 
					 | 
				
			||||||
	ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(ports) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(ports))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(bindings) != 1 {
 | 
					 | 
				
			||||||
		t.Logf("Expected 1 got %d", len(bindings))
 | 
					 | 
				
			||||||
		t.FailNow()
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for k := range ports {
 | 
					 | 
				
			||||||
		if k.Proto() != "udp" {
 | 
					 | 
				
			||||||
			t.Logf("Expected udp got %s", k.Proto())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if k.Port() != "6000" {
 | 
					 | 
				
			||||||
			t.Logf("Expected 6000 got %s", k.Port())
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		b, exists := bindings[k]
 | 
					 | 
				
			||||||
		if !exists {
 | 
					 | 
				
			||||||
			t.Log("Binding does not exist")
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(b) != 1 {
 | 
					 | 
				
			||||||
			t.Logf("Expected 1 got %d", len(b))
 | 
					 | 
				
			||||||
			t.FailNow()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		s := b[0]
 | 
					 | 
				
			||||||
		if s.HostPort != "" {
 | 
					 | 
				
			||||||
			t.Logf("Expected \"\" got %s", s.HostPort)
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if s.HostIp != "192.168.1.100" {
 | 
					 | 
				
			||||||
			t.Fail()
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue