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 builder_server-3

Conflicts:
	utils/utils.go
This commit is contained in:
Guillaume J. Charmes 2013-06-14 17:08:39 -07:00
commit 78f86ea502
24 changed files with 309 additions and 44 deletions

12
FIXME
View file

@ -16,3 +16,15 @@ to put them - so we put them here :)
* Unify build commands and regular commands * Unify build commands and regular commands
* Move source code into src/ subdir for clarity * Move source code into src/ subdir for clarity
* Clean up the Makefile, it's a mess * Clean up the Makefile, it's a mess
- docker buidl: show short IDs
- docker build: on non-existent local path for ADD, don't show full absolute path on the host
- mount into /dockerinit rather than /sbin/init
- docker tag foo REPO:TAG
- use size header for progress bar in pull
- Clean up context upload in build!!!
- Parallel pull
- Ensure /proc/sys/net/ipv4/ip_forward is 1
- Force DNS to public!
- Always generate a resolv.conf per container, to avoid changing resolv.conf under thne container's feet
- Save metadata with import/export
- Upgrade dockerd without stopping containers

16
Vagrantfile vendored
View file

@ -5,11 +5,13 @@ BOX_NAME = ENV['BOX_NAME'] || "ubuntu"
BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box" BOX_URI = ENV['BOX_URI'] || "http://files.vagrantup.com/precise64.box"
AWS_REGION = ENV['AWS_REGION'] || "us-east-1" AWS_REGION = ENV['AWS_REGION'] || "us-east-1"
AWS_AMI = ENV['AWS_AMI'] || "ami-d0f89fb9" AWS_AMI = ENV['AWS_AMI'] || "ami-d0f89fb9"
FORWARD_DOCKER_PORTS = ENV['FORWARD_DOCKER_PORTS']
Vagrant::Config.run do |config| Vagrant::Config.run do |config|
# Setup virtual machine box. This VM configuration code is always executed. # Setup virtual machine box. This VM configuration code is always executed.
config.vm.box = BOX_NAME config.vm.box = BOX_NAME
config.vm.box_url = BOX_URI config.vm.box_url = BOX_URI
config.vm.forward_port 4243, 4243
# Provision docker and new kernel if deployment was not done # Provision docker and new kernel if deployment was not done
if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty? if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty?
@ -70,3 +72,17 @@ Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
config.vm.box_url = BOX_URI config.vm.box_url = BOX_URI
end end
end end
if !FORWARD_DOCKER_PORTS.nil?
Vagrant::VERSION < "1.1.0" and Vagrant::Config.run do |config|
(49000..49900).each do |port|
config.vm.forward_port port, port
end
end
Vagrant::VERSION >= "1.1.0" and Vagrant.configure("2") do |config|
(49000..49900).each do |port|
config.vm.network :forwarded_port, :host => port, :guest => port
end
end
end

13
api.go
View file

@ -438,17 +438,23 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error { func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
config := &Config{} config := &Config{}
out := &APIRun{}
if err := json.NewDecoder(r.Body).Decode(config); err != nil { if err := json.NewDecoder(r.Body).Decode(config); err != nil {
return err return err
} }
if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns() {
out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns))
config.Dns = defaultDns
}
id, err := srv.ContainerCreate(config) id, err := srv.ContainerCreate(config)
if err != nil { if err != nil {
return err return err
} }
out.ID = id
out := &APIRun{
ID: id,
}
if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit { if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.") log.Println("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.")
out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.") out.Warnings = append(out.Warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
@ -457,6 +463,7 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.") log.Println("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.")
out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.") out.Warnings = append(out.Warnings, "Your kernel does not support memory swap capabilities. Limitation discarded.")
} }
b, err := json.Marshal(out) b, err := json.Marshal(out)
if err != nil { if err != nil {
return err return err

View file

@ -11,6 +11,8 @@ type APIImages struct {
Tag string `json:",omitempty"` Tag string `json:",omitempty"`
ID string `json:"Id"` ID string `json:"Id"`
Created int64 Created int64
Size int64
VirtualSize int64
} }
type APIInfo struct { type APIInfo struct {
@ -35,6 +37,8 @@ type APIContainers struct {
Created int64 Created int64
Status string Status string
Ports string Ports string
SizeRw int64
SizeRootFs int64
} }
type APISearch struct { type APISearch struct {

View file

@ -2,11 +2,14 @@ package docker
import ( import (
"fmt" "fmt"
"github.com/dotcloud/docker/utils"
"os" "os"
"path" "path"
"time" "time"
) )
var defaultDns = []string{"8.8.8.8", "8.8.4.4"}
type Builder struct { type Builder struct {
runtime *Runtime runtime *Runtime
repositories *TagStore repositories *TagStore
@ -66,15 +69,26 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
return nil, err return nil, err
} }
if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns() {
//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
builder.runtime.Dns = defaultDns
}
// If custom dns exists, then create a resolv.conf for the container // If custom dns exists, then create a resolv.conf for the container
if len(config.Dns) > 0 || len(builder.runtime.Dns) > 0 {
var dns []string
if len(config.Dns) > 0 { if len(config.Dns) > 0 {
dns = config.Dns
} else {
dns = builder.runtime.Dns
}
container.ResolvConfPath = path.Join(container.root, "resolv.conf") container.ResolvConfPath = path.Join(container.root, "resolv.conf")
f, err := os.Create(container.ResolvConfPath) f, err := os.Create(container.ResolvConfPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer f.Close() defer f.Close()
for _, dns := range config.Dns { for _, dns := range dns {
if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil { if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil {
return nil, err return nil, err
} }

View file

@ -20,6 +20,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"strings" "strings"
"syscall" "syscall"
@ -736,6 +737,15 @@ func (cli *DockerCli) CmdPush(args ...string) error {
if err != nil { if err != nil {
return err 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 := url.Values{}
v.Set("registry", *registry) v.Set("registry", *registry)
@ -820,7 +830,7 @@ func (cli *DockerCli) CmdImages(args ...string) error {
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
if !*quiet { if !*quiet {
fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED") fmt.Fprintln(w, "REPOSITORY\tTAG\tID\tCREATED\tSIZE")
} }
for _, out := range outs { for _, out := range outs {
@ -838,7 +848,12 @@ func (cli *DockerCli) CmdImages(args ...string) error {
} else { } else {
fmt.Fprintf(w, "%s\t", utils.TruncateID(out.ID)) 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 { } else {
if *noTrunc { if *noTrunc {
fmt.Fprintln(w, out.ID) fmt.Fprintln(w, out.ID)
@ -897,15 +912,20 @@ func (cli *DockerCli) CmdPs(args ...string) error {
} }
w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
if !*quiet { 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 { for _, out := range outs {
if !*quiet { if !*quiet {
if *noTrunc { 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 { } 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 { } else {
if *noTrunc { if *noTrunc {

View file

@ -13,6 +13,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -919,3 +920,26 @@ func validateID(id string) error {
} }
return nil 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

@ -34,6 +34,7 @@ func main() {
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID") pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to") flHost := flag.String("H", fmt.Sprintf("%s:%d", host, port), "Host:port to bind/connect to")
flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.") flEnableCors := flag.Bool("api-enable-cors", false, "Enable CORS requests in the remote api.")
flDns := flag.String("dns", "", "Set custom dns servers")
flag.Parse() flag.Parse()
if *bridgeName != "" { if *bridgeName != "" {
docker.NetworkBridgeIface = *bridgeName docker.NetworkBridgeIface = *bridgeName
@ -66,7 +67,7 @@ func main() {
flag.Usage() flag.Usage()
return return
} }
if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors); err != nil { if err := daemon(*pidfile, host, port, *flAutoRestart, *flEnableCors, *flDns); err != nil {
log.Fatal(err) log.Fatal(err)
os.Exit(-1) os.Exit(-1)
} }
@ -105,7 +106,7 @@ func removePidFile(pidfile string) {
} }
} }
func daemon(pidfile, addr string, port int, autoRestart, enableCors bool) error { func daemon(pidfile, addr string, port int, autoRestart, enableCors bool, flDns string) error {
if addr != "127.0.0.1" { if addr != "127.0.0.1" {
log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") log.Println("/!\\ DON'T BIND ON ANOTHER IP ADDRESS THAN 127.0.0.1 IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
} }
@ -122,8 +123,11 @@ func daemon(pidfile, addr string, port int, autoRestart, enableCors bool) error
removePidFile(pidfile) removePidFile(pidfile)
os.Exit(0) os.Exit(0)
}() }()
var dns []string
server, err := docker.NewServer(autoRestart, enableCors) if flDns != "" {
dns = []string{flDns}
}
server, err := docker.NewServer(autoRestart, enableCors, dns)
if err != nil { if err != nil {
return err return err
} }

View file

@ -47,28 +47,40 @@ List containers
"Image": "base:latest", "Image": "base:latest",
"Command": "echo 1", "Command": "echo 1",
"Created": 1367854155, "Created": 1367854155,
"Status": "Exit 0" "Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
}, },
{ {
"Id": "9cd87474be90", "Id": "9cd87474be90",
"Image": "base:latest", "Image": "base:latest",
"Command": "echo 222222", "Command": "echo 222222",
"Created": 1367854155, "Created": 1367854155,
"Status": "Exit 0" "Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
}, },
{ {
"Id": "3176a2479c92", "Id": "3176a2479c92",
"Image": "base:latest", "Image": "base:latest",
"Command": "echo 3333333333333333", "Command": "echo 3333333333333333",
"Created": 1367854154, "Created": 1367854154,
"Status": "Exit 0" "Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
}, },
{ {
"Id": "4cb07b47f9fb", "Id": "4cb07b47f9fb",
"Image": "base:latest", "Image": "base:latest",
"Command": "echo 444444444444444444444444444444444", "Command": "echo 444444444444444444444444444444444",
"Created": 1367854152, "Created": 1367854152,
"Status": "Exit 0" "Status": "Exit 0",
"Ports":"",
"SizeRw":12288,
"SizeRootFs":0
} }
] ]
@ -488,13 +500,17 @@ List Images
"Repository":"base", "Repository":"base",
"Tag":"ubuntu-12.10", "Tag":"ubuntu-12.10",
"Id":"b750fe79269d", "Id":"b750fe79269d",
"Created":1364102658 "Created":1364102658,
"Size":24653,
"VirtualSize":180116135
}, },
{ {
"Repository":"base", "Repository":"base",
"Tag":"ubuntu-quantal", "Tag":"ubuntu-quantal",
"Id":"b750fe79269d", "Id":"b750fe79269d",
"Created":1364102658 "Created":1364102658,
"Size":24653,
"VirtualSize":180116135
} }
] ]
@ -643,7 +659,8 @@ Inspect an image
"Image":"base", "Image":"base",
"Volumes":null, "Volumes":null,
"VolumesFrom":"" "VolumesFrom":""
} },
"Size": 6824592
} }
:statuscode 200: no error :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 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 apt-get install python-software-properties
sudo add-apt-repository ppa:gophers/go sudo add-apt-repository ppa:gophers/go
sudo apt-get update sudo apt-get update
sudo apt-get -y install lxc wget bsdtar curl golang-stable git sudo apt-get -y install lxc wget bsdtar curl golang-stable git aufs-tools
export GOPATH=~/go/ export GOPATH=~/go/
export PATH=$GOPATH/bin:$PATH 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) return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.ID)
} }
img.graph = graph 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() graph.lockSumMap.Lock()
defer graph.lockSumMap.Unlock() defer graph.lockSumMap.Unlock()
if _, exists := graph.checksumLock[img.ID]; !exists { 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}; " pkg_cmd = "touch #{DOCKER_PATH}; "
# Install docker dependencies # Install docker dependencies
pkg_cmd << "export DEBIAN_FRONTEND=noninteractive; apt-get -qq update; " \ 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}; " \ "chown -R #{USER}.#{USER} #{GOPATH}; " \
"install -m 0664 #{CFG_PATH}/bash_profile /home/#{USER}/.bash_profile" "install -m 0664 #{CFG_PATH}/bash_profile /home/#{USER}/.bash_profile"
config.vm.provision :shell, :inline => pkg_cmd config.vm.provision :shell, :inline => pkg_cmd

View file

@ -13,6 +13,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"strings" "strings"
"time" "time"
) )
@ -29,6 +30,7 @@ type Image struct {
Config *Config `json:"config,omitempty"` Config *Config `json:"config,omitempty"`
Architecture string `json:"architecture,omitempty"` Architecture string `json:"architecture,omitempty"`
graph *Graph graph *Graph
Size int64
} }
func LoadImage(root string) (*Image, error) { 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 { if err := Untar(layerData, layer); err != nil {
return err 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 // Store the json ball
jsonData, err := json.Marshal(img) jsonData, err := json.Marshal(img)
if err != nil { if err != nil {
@ -363,6 +377,15 @@ func (img *Image) Checksum() (string, error) {
return hash, nil 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 // Build an Image object from raw json data
func NewImgJSON(src []byte) (*Image, error) { func NewImgJSON(src []byte) (*Image, error) {
ret := &Image{} ret := &Image{}

View file

@ -2,13 +2,18 @@ package docker
import ( import (
"fmt" "fmt"
"github.com/dotcloud/docker/utils"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"syscall" "syscall"
"time" "time"
) )
func Unmount(target string) error { 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 { if err := syscall.Unmount(target, 0); err != nil {
return err return err
} }

View file

@ -10,7 +10,7 @@ Homepage: http://github.com/dotcloud/docker
Package: lxc-docker Package: lxc-docker
Architecture: linux-any Architecture: linux-any
Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar Depends: ${shlibs:Depends}, ${misc:Depends}, lxc, bsdtar, aufs-tools
Description: Linux container runtime Description: Linux container runtime
Docker complements LXC with a high-level API which operates at the process Docker complements LXC with a high-level API which operates at the process
level. It runs unix processes with strong guarantees of isolation and 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 Package: lxc-docker
Architecture: linux-any Architecture: linux-any
Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar Depends: ${misc:Depends},${shlibs:Depends},lxc,bsdtar,aufs-tools
Conflicts: docker Conflicts: docker
Description: lxc-docker is a Linux container runtime Description: lxc-docker is a Linux container runtime
Docker complements LXC with a high-level API which operates at the process 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 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) imgListJSON, err := json.Marshal(imgList)
if err != nil { if err != nil {
return nil, err 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.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON)) req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true") req.Header.Set("X-Docker-Token", "true")
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
res, err := r.client.Do(req) res, err := r.client.Do(req)
if err != nil { 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.SetBasicAuth(r.authConfig.Username, r.authConfig.Password)
req.ContentLength = int64(len(imgListJSON)) req.ContentLength = int64(len(imgListJSON))
req.Header.Set("X-Docker-Token", "true") req.Header.Set("X-Docker-Token", "true")
if validate {
req.Header["X-Docker-Endpoints"] = regs
}
res, err = r.client.Do(req) res, err = r.client.Do(req)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -32,6 +32,7 @@ type Runtime struct {
autoRestart bool autoRestart bool
volumes *Graph volumes *Graph
srv *Server srv *Server
Dns []string
} }
var sysInitPath string var sysInitPath string
@ -245,11 +246,12 @@ func (runtime *Runtime) UpdateCapabilities(quiet bool) {
} }
// FIXME: harmonize with NewGraph() // FIXME: harmonize with NewGraph()
func NewRuntime(autoRestart bool) (*Runtime, error) { func NewRuntime(autoRestart bool, dns []string) (*Runtime, error) {
runtime, err := NewRuntimeFromDirectory("/var/lib/docker", autoRestart) runtime, err := NewRuntimeFromDirectory("/var/lib/docker", autoRestart)
if err != nil { if err != nil {
return nil, err return nil, err
} }
runtime.Dns = dns
if k, err := utils.GetKernelVersion(); err != nil { if k, err := utils.GetKernelVersion(); err != nil {
log.Printf("WARNING: %s\n", err) log.Printf("WARNING: %s\n", err)

View file

@ -174,6 +174,8 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
out.Tag = tag out.Tag = tag
out.ID = image.ID out.ID = image.ID
out.Created = image.Created.Unix() out.Created = image.Created.Unix()
out.Size = image.Size
out.VirtualSize = image.getParentsSize(0) + image.Size
outs = append(outs, out) outs = append(outs, out)
} }
} }
@ -183,6 +185,8 @@ func (srv *Server) Images(all bool, filter string) ([]APIImages, error) {
var out APIImages var out APIImages
out.ID = image.ID out.ID = image.ID
out.Created = image.Created.Unix() out.Created = image.Created.Unix()
out.Size = image.Size
out.VirtualSize = image.getParentsSize(0) + image.Size
outs = append(outs, out) 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.Created = container.Created.Unix()
c.Status = container.State.String() c.Status = container.State.String()
c.Ports = container.NetworkSettings.PortMappingHuman() c.Ports = container.NetworkSettings.PortMappingHuman()
c.SizeRw, c.SizeRootFs = container.GetSize()
retContainers = append(retContainers, c) retContainers = append(retContainers, c)
} }
return retContainers 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, "/"))) 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 { if err != nil {
return err 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 err
} }
return nil 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) { 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 { if config.Memory > 0 && !srv.runtime.capabilities.MemoryLimit {
config.Memory = 0 config.Memory = 0
} }
@ -972,11 +982,11 @@ func (srv *Server) ImageInspect(name string) (*Image, error) {
return nil, fmt.Errorf("No such image: %s", name) return nil, fmt.Errorf("No such image: %s", name)
} }
func NewServer(autoRestart, enableCors bool) (*Server, error) { func NewServer(autoRestart, enableCors bool, dns ListOpts) (*Server, error) {
if runtime.GOARCH != "amd64" { if runtime.GOARCH != "amd64" {
log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH) log.Fatalf("The docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
} }
runtime, err := NewRuntime(autoRestart) runtime, err := NewRuntime(autoRestart, dns)
if err != nil { if err != nil {
return nil, err return nil, err
} }

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 # Install docker dependencies
pkg_cmd << "apt-get install -q -y python-software-properties; " \ pkg_cmd << "apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:gophers/go/ubuntu; apt-get update -qq; " \ "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 # Activate new kernel
pkg_cmd << "shutdown -r +1; " pkg_cmd << "shutdown -r +1; "
config.vm.provision :shell, :inline => pkg_cmd 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) 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 { func Trunc(s string, maxlen int) string {
if len(s) <= maxlen { if len(s) <= maxlen {
return s return s
@ -628,3 +642,20 @@ func IsURL(str string) bool {
func IsGIT(str string) bool { func IsGIT(str string) bool {
return strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "github.com/") return strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "github.com/")
} }
func CheckLocalDns() bool {
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
Debugf("Error openning resolv.conf: %s", err)
return false
}
for _, ip := range []string{
"127.0.0.1",
"127.0.1.1",
} {
if strings.Contains(string(resolv), ip) {
return true
}
}
return false
}

View file

@ -261,3 +261,16 @@ func TestCompareKernelVersion(t *testing.T) {
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"}, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
-1) -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)
}
}