1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge branch 'master' into remove_bsdtar

Conflicts:
	docs/sources/contributing/devenvironment.rst
This commit is contained in:
Guillaume J. Charmes 2013-06-14 14:34:30 -07:00
commit abf85b2508
18 changed files with 225 additions and 32 deletions

View file

@ -7,10 +7,12 @@ type APIHistory struct {
}
type APIImages struct {
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
ID string `json:"Id"`
Created int64
Repository string `json:",omitempty"`
Tag string `json:",omitempty"`
ID string `json:"Id"`
Created int64
Size int64
VirtualSize int64
}
type APIInfo struct {
@ -29,12 +31,14 @@ type APIRmi struct {
}
type APIContainers struct {
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports string
ID string `json:"Id"`
Image string
Command string
Created int64
Status string
Ports string
SizeRw int64
SizeRootFs int64
}
type APISearch struct {

View file

@ -20,6 +20,7 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"syscall"
@ -727,6 +728,15 @@ func (cli *DockerCli) CmdPush(args ...string) error {
if err != nil {
return err
}
nameParts := strings.SplitN(name, "/", 2)
validNamespace := regexp.MustCompile(`^([a-z0-9_]{4,30})$`)
if !validNamespace.MatchString(nameParts[0]) {
return fmt.Errorf("Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", nameParts[0])
}
validRepo := regexp.MustCompile(`^([a-zA-Z0-9-_.]+)$`)
if !validRepo.MatchString(nameParts[1]) {
return fmt.Errorf("Invalid repository name (%s), only [a-zA-Z0-9-_.] are allowed", nameParts[1])
}
v := url.Values{}
v.Set("registry", *registry)
@ -811,7 +821,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED")
fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tSIZE")
}
for _, out := range outs {
@ -829,7 +839,12 @@ func (cli *DockerCli) CmdImages(args ...string) error {
} else {
fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID))
}
fmt.Fprintf(w, "%s ago\n", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
fmt.Fprintf(w, "%s ago\t", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
if out.VirtualSize > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.Size), utils.HumanSize(out.VirtualSize))
} else {
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.Size))
}
} else {
if *noTrunc {
fmt.Fprintln(w, out.ID)
@ -888,15 +903,20 @@ func (cli *DockerCli) CmdPs(args ...string) error {
}
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS")
fmt.Fprintln(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tSIZE")
}
for _, out := range outs {
if !*quiet {
if *noTrunc {
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", out.ID, out.Image, out.Command, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
} else {
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\n", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t", utils.TruncateID(out.ID), out.Image, utils.Trunc(out.Command, 20), utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Status, out.Ports)
}
if out.SizeRootFs > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", utils.HumanSize(out.SizeRw), utils.HumanSize(out.SizeRootFs))
} else {
fmt.Fprintf(w, "%s\n", utils.HumanSize(out.SizeRw))
}
} else {
if *noTrunc {

View file

@ -13,6 +13,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
@ -919,3 +920,26 @@ func validateID(id string) error {
}
return nil
}
// GetSize, return real size, virtual size
func (container *Container) GetSize() (int64, int64) {
var sizeRw, sizeRootfs int64
filepath.Walk(container.rwPath(), func(path string, fileInfo os.FileInfo, err error) error {
if fileInfo != nil {
sizeRw += fileInfo.Size()
}
return nil
})
_, err := os.Stat(container.RootfsPath())
if err == nil {
filepath.Walk(container.RootfsPath(), func(path string, fileInfo os.FileInfo, err error) error {
if fileInfo != nil {
sizeRootfs += fileInfo.Size()
}
return nil
})
}
return sizeRw, sizeRootfs
}

View file

@ -47,28 +47,40 @@ List containers
"Image": "base:latest",
"Command": "echo 1",
"Created": 1367854155,
"Status": "Exit 0"
"Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
},
{
"Id": "9cd87474be90",
"Image": "base:latest",
"Command": "echo 222222",
"Created": 1367854155,
"Status": "Exit 0"
"Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
},
{
"Id": "3176a2479c92",
"Image": "base:latest",
"Command": "echo 3333333333333333",
"Created": 1367854154,
"Status": "Exit 0"
"Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
},
{
"Id": "4cb07b47f9fb",
"Image": "base:latest",
"Command": "echo 444444444444444444444444444444444",
"Created": 1367854152,
"Status": "Exit 0"
"Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
}
]
@ -488,13 +500,17 @@ List Images
"Repository":"base",
"Tag":"ubuntu-12.10",
"Id":"b750fe79269d",
"Created":1364102658
"Created":1364102658,
"Size":24653,
"VirtualSize":180116135
},
{
"Repository":"base",
"Tag":"ubuntu-quantal",
"Id":"b750fe79269d",
"Created":1364102658
"Created":1364102658,
"Size":24653,
"VirtualSize":180116135
}
]
@ -643,7 +659,8 @@ Inspect an image
"Image":"base",
"Volumes":null,
"VolumesFrom":""
}
},
"Size": 6824592
}
:statuscode 200: no error

View file

@ -8,6 +8,33 @@
::
Usage: docker import [OPTIONS] URL|- [REPOSITORY [TAG]]
Usage: docker import URL|- [REPOSITORY [TAG]]
Create a new filesystem image from the contents of a tarball
At this time, the URL must start with ``http`` and point to a single file archive (.tar, .tar.gz, .bzip)
containing a root filesystem. If you would like to import from a local directory or archive,
you can use the ``-`` parameter to take the data from standard in.
Examples
--------
Import from a remote location
.............................
``$ docker import http://example.com/exampleimage.tgz exampleimagerepo``
Import from a local file
........................
Import to docker via pipe and standard in
``$ cat exampleimage.tgz | docker import - exampleimagelocal``
Import from a local directory
.............................
``$ sudo tar -c . | docker import - exampleimagedir``
Note the ``sudo`` in this example -- you must preserve the ownership of the files (especially root ownership)
during the archiving with tar. If you are not root (or sudo) when you tar, then the ownerships might not get preserved.

View file

@ -33,7 +33,7 @@ Installation
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:gophers/go
sudo apt-get update
sudo apt-get -y install lxc xz-utils curl golang-stable git
sudo apt-get -y install lxc xz-utils curl golang-stable git aufs-tools
export GOPATH=~/go/
export PATH=$GOPATH/bin:$PATH

View file

@ -90,6 +90,15 @@ func (graph *Graph) Get(name string) (*Image, error) {
return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
}
img.graph = graph
if img.Size == 0 {
root, err := img.root()
if err != nil {
return nil, err
}
if err := StoreSize(img, root); err != nil {
return nil, err
}
}
graph.lockSumMap.Lock()
defer graph.lockSumMap.Unlock()
if _, exists := graph.checksumLock[img.ID]; !exists {

2
hack/Vagrantfile vendored
View file

@ -22,7 +22,7 @@ Vagrant::Config.run do |config|
pkg_cmd = "touch #{DOCKER_PATH}; "
# Install docker dependencies
pkg_cmd << "export DEBIAN_FRONTEND=noninteractive; apt-get -qq update; " \
"apt-get install -q -y lxc bsdtar git golang make linux-image-extra-3.8.0-19-generic; " \
"apt-get install -q -y lxc bsdtar git aufs-tools golang make linux-image-extra-3.8.0-19-generic; " \
"chown -R #{USER}.#{USER} #{GOPATH}; " \
"install -m 0664 #{CFG_PATH}/bash_profile /home/#{USER}/.bash_profile"
config.vm.provision :shell, :inline => pkg_cmd

View file

@ -13,6 +13,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
)
@ -29,6 +30,7 @@ type Image struct {
Config *Config `json:"config,omitempty"`
Architecture string `json:"architecture,omitempty"`
graph *Graph
Size int64
}
func LoadImage(root string) (*Image, error) {
@ -94,6 +96,18 @@ func StoreImage(img *Image, layerData Archive, root string, store bool) error {
if err := Untar(layerData, layer); err != nil {
return err
}
return StoreSize(img, root)
}
func StoreSize(img *Image, root string) error {
layer := layerPath(root)
filepath.Walk(layer, func(path string, fileInfo os.FileInfo, err error) error {
img.Size += fileInfo.Size()
return nil
})
// Store the json ball
jsonData, err := json.Marshal(img)
if err != nil {
@ -363,6 +377,15 @@ func (img *Image) Checksum() (string, error) {
return hash, nil
}
func (img *Image) getParentsSize(size int64) int64 {
parentImage, err := img.GetParent()
if err != nil || parentImage == nil {
return size
}
size += parentImage.Size
return parentImage.getParentsSize(size)
}
// Build an Image object from raw json data
func NewImgJSON(src []byte) (*Image, error) {
ret := &Image{}

View file

@ -2,13 +2,18 @@ package docker
import (
"fmt"
"github.com/dotcloud/docker/utils"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"
)
func Unmount(target string) error {
if err := exec.Command("auplink", target, "flush").Run(); err != nil {
utils.Debugf("[warning]: couldn't run auplink before unmount: %s", err)
}
if err := syscall.Unmount(target, 0); err != nil {
return err
}

View file

@ -10,7 +10,7 @@ Homepage: http://github.com/dotcloud/docker
Package: lxc-docker
Architecture: linux-any
Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar
Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar, aufs-tools
Description: Linux container runtime
Docker complements LXC with a high-level API which operates at the process
level. It runs unix processes with strong guarantees of isolation and

View file

@ -8,7 +8,7 @@ Homepage: http://github.com/dotcloud/docker
Package: lxc-docker
Architecture: linux-any
Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar
Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar,aufs-tools
Conflicts: docker
Description: lxc-docker is a Linux container runtime
Docker complements LXC with a high-level API which operates at the process

View file

@ -328,7 +328,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
return nil
}
func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool) (*RepositoryData, error) {
func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
imgListJSON, err := json.Marshal(imgList)
if err != nil {
return nil, err
@ -347,6 +347,9 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true")
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
res, err := r.client.Do(req)
if err != nil {
@ -364,7 +367,9 @@ func (r *Registry) PushImageJSONIndex(remote string, imgList []*ImgData, validat
req.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true")
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
res, err = r.client.Do(req)
if err != nil {
return nil, err

View file

@ -174,6 +174,8 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
out.Tag = tag
out.ID = image.ID
out.Created = image.Created.Unix()
out.Size = image.Size
out.VirtualSize = image.getParentsSize(0) + image.Size
outs = append(outs, out)
}
}
@ -183,6 +185,8 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
var out APIImages
out.ID = image.ID
out.Created = image.Created.Unix()
out.Size = image.Size
out.VirtualSize = image.getParentsSize(0) + image.Size
outs = append(outs, out)
}
}
@ -268,6 +272,8 @@ func (srv *Server) Containers(all bool, n int, since, before string) []APIContai
c.Created = container.Created.Unix()
c.Status = container.State.String()
c.Ports = container.NetworkSettings.PortMappingHuman()
c.SizeRw, c.SizeRootFs = container.GetSize()
retContainers = append(retContainers, c)
}
return retContainers
@ -497,7 +503,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri
srvName = fmt.Sprintf("src/%s", url.QueryEscape(strings.Join(parts, "/")))
}
repoData, err := r.PushImageJSONIndex(srvName, imgList, false)
repoData, err := r.PushImageJSONIndex(srvName, imgList, false, nil)
if err != nil {
return err
}
@ -521,7 +527,7 @@ func (srv *Server) pushRepository(r *registry.Registry, out io.Writer, name stri
}
}
if _, err := r.PushImageJSONIndex(srvName, imgList, true); err != nil {
if _, err := r.PushImageJSONIndex(srvName, imgList, true, repoData.Endpoints); err != nil {
return err
}
return nil
@ -652,6 +658,10 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
func (srv *Server) ContainerCreate(config *Config) (string, error) {
if config.Memory != 0 && config.Memory < 524288 {
return "", fmt.Errorf("Memory limit must be given in bytes (minimum 524288 bytes)")
}
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
config.Memory = 0
}

View file

@ -147,3 +147,25 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
}
}
func TestRunWithTooLowMemoryLimit(t *testing.T) {
runtime, err := newTestRuntime()
srv := &Server{runtime: runtime}
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
// Try to create a container with a memory limit of 1 byte less than the minimum allowed limit.
_, err = srv.ContainerCreate(
&Config{
Image: GetTestImage(runtime).ID,
Memory: 524287,
CpuShares: 1000,
Cmd: []string{"/bin/cat"},
},
)
if err == nil {
t.Errorf("Memory limit is smaller than the allowed limit. Container creation should've failed!")
}
}

2
testing/Vagrantfile vendored
View file

@ -30,7 +30,7 @@ Vagrant::Config.run do |config|
# Install docker dependencies
pkg_cmd << "apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:gophers/go/ubuntu; apt-get update -qq; " \
"DEBIAN_FRONTEND=noninteractive apt-get install -q -y lxc bsdtar git golang-stable make; "
"DEBIAN_FRONTEND=noninteractive apt-get install -q -y lxc bsdtar git golang-stable aufs-tools make; "
# Activate new kernel
pkg_cmd << "shutdown -r +1; "
config.vm.provision :shell, :inline => pkg_cmd

View file

@ -135,6 +135,20 @@ func HumanDuration(d time.Duration) string {
return fmt.Sprintf("%d years", d.Hours()/24/365)
}
// HumanSize returns a human-readable approximation of a size
// using SI standard (eg. "44kB", "17MB")
func HumanSize(size int64) string {
i := 0
var sizef float64
sizef = float64(size)
units := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
for sizef >= 1000.0 {
sizef = sizef / 1000.0
i++
}
return fmt.Sprintf("%.4g %s", sizef, units[i])
}
func Trunc(s string, maxlen int) string {
if len(s) <= maxlen {
return s

View file

@ -261,3 +261,16 @@ func TestCompareKernelVersion(t *testing.T) {
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
-1)
}
func TestHumanSize(t *testing.T) {
size1000 := HumanSize(1000)
if size1000 != "1 kB" {
t.Errorf("1000 -> expected 1 kB, got %s", size1000)
}
size1024 := HumanSize(1024)
if size1024 != "1.024 kB" {
t.Errorf("1024 -> expected 1.024 kB, got %s", size1024)
}
}