1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
This commit is contained in:
Victor Vieux 2013-08-05 11:07:27 +00:00
commit a97cf23355
27 changed files with 387 additions and 98 deletions

View file

@ -50,6 +50,7 @@ release: $(BINRELEASE)
s3cmd -P put $(BINRELEASE) s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-$(RELEASE_VERSION).tgz
s3cmd -P put docker-latest.tgz s3://get.docker.io/builds/`uname -s`/`uname -m`/docker-latest.tgz
s3cmd -P put $(SRCRELEASE)/bin/docker s3://get.docker.io/builds/`uname -s`/`uname -m`/docker
echo $(RELEASE_VERSION) > latest ; s3cmd -P put latest s3://get.docker.io/latest ; rm latest
srcrelease: $(SRCRELEASE)
deps: $(DOCKER_DIR)
@ -65,7 +66,6 @@ $(BINRELEASE): $(SRCRELEASE)
rm -f $(BINRELEASE)
cd $(SRCRELEASE); make; cp -R bin docker-$(RELEASE_VERSION); tar -f ../$(BINRELEASE) -zv -c docker-$(RELEASE_VERSION)
cd $(SRCRELEASE); cp -R bin docker-latest; tar -f ../docker-latest.tgz -zv -c docker-latest
clean:
@rm -rf $(dir $(DOCKER_BIN))
ifeq ($(GOPATH), $(BUILD_DIR))

2
Vagrantfile vendored
View file

@ -20,8 +20,6 @@ Vagrant::Config.run do |config|
pkg_cmd = "apt-get update -qq; apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:dotcloud/lxc-docker; apt-get update -qq; " \
"apt-get install -q -y lxc-docker; "
# Listen on all interfaces so that the daemon is accessible from the host
pkg_cmd << "sed -i -E 's| /usr/bin/docker -d| /usr/bin/docker -d -H 0.0.0.0|' /etc/init/docker.conf;"
# Add X.org Ubuntu backported 3.8 kernel
pkg_cmd << "add-apt-repository -y ppa:ubuntu-x-swat/r-lts-backport; " \
"apt-get update -qq; apt-get install -q -y linux-image-3.8.0-19-generic; "

14
api.go
View file

@ -488,7 +488,12 @@ func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r
return err
}
if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns() {
resolvConf, err := utils.GetResolvConf()
if err != nil {
return err
}
if len(config.Dns) == 0 && len(srv.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
out.Warnings = append(out.Warnings, fmt.Sprintf("Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns))
config.Dns = defaultDns
}
@ -793,6 +798,7 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
remoteURL := r.FormValue("remote")
repoName := r.FormValue("t")
rawSuppressOutput := r.FormValue("q")
rawNoCache := r.FormValue("nocache")
repoName, tag := utils.ParseRepositoryTag(repoName)
var context io.Reader
@ -839,8 +845,12 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
if err != nil {
return err
}
noCache, err := getBoolParam(rawNoCache)
if err != nil {
return err
}
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput)
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache)
id, err := b.Build(context)
if err != nil {
fmt.Fprintf(w, "Error build: %s\n", err)

View file

@ -173,7 +173,7 @@ func CopyWithTar(src, dst string) error {
}
// Create dst, copy src's content into it
utils.Debugf("Creating dest directory: %s", dst)
if err := os.MkdirAll(dst, 0700); err != nil && !os.IsExist(err) {
if err := os.MkdirAll(dst, 0755); err != nil && !os.IsExist(err) {
return err
}
utils.Debugf("Calling TarUntar(%s, %s)", src, dst)

View file

@ -80,7 +80,12 @@ func (builder *Builder) Create(config *Config) (*Container, error) {
return nil, err
}
if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns() {
resolvConf, err := utils.GetResolvConf()
if err != nil {
return nil, err
}
if len(config.Dns) == 0 && len(builder.runtime.Dns) == 0 && utils.CheckLocalDns(resolvConf) {
//"WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: %v", defaultDns
builder.runtime.Dns = defaultDns
}

View file

@ -26,11 +26,12 @@ type buildFile struct {
builder *Builder
srv *Server
image string
maintainer string
config *Config
context string
verbose bool
image string
maintainer string
config *Config
context string
verbose bool
utilizeCache bool
tmpContainers map[string]struct{}
tmpImages map[string]struct{}
@ -94,15 +95,17 @@ func (b *buildFile) CmdRun(args string) error {
utils.Debugf("Command to be executed: %v", b.config.Cmd)
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
fmt.Fprintf(b.out, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
} else {
utils.Debugf("[BUILDER] Cache miss")
if b.utilizeCache {
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
fmt.Fprintf(b.out, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
} else {
utils.Debugf("[BUILDER] Cache miss")
}
}
cid, err := b.run()
@ -397,16 +400,19 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
b.config.Cmd = []string{"/bin/sh", "-c", "#(nop) " + comment}
defer func(cmd []string) { b.config.Cmd = cmd }(cmd)
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
fmt.Fprintf(b.out, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
} else {
utils.Debugf("[BUILDER] Cache miss")
if b.utilizeCache {
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
fmt.Fprintf(b.out, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
} else {
utils.Debugf("[BUILDER] Cache miss")
}
}
container, err := b.builder.Create(b.config)
if err != nil {
return err
@ -500,7 +506,7 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
return "", fmt.Errorf("An error occured during the build\n")
}
func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache bool) BuildFile {
return &buildFile{
builder: NewBuilder(srv.runtime),
runtime: srv.runtime,
@ -510,5 +516,6 @@ func NewBuildFile(srv *Server, out io.Writer, verbose bool) BuildFile {
tmpContainers: make(map[string]struct{}),
tmpImages: make(map[string]struct{}),
verbose: verbose,
utilizeCache: utilizeCache,
}
}

View file

@ -195,21 +195,23 @@ func mkTestingFileServer(files [][2]string) (*httptest.Server, error) {
func TestBuild(t *testing.T) {
for _, ctx := range testContexts {
buildImage(ctx, t)
buildImage(ctx, t, nil, true)
}
}
func buildImage(context testContextTemplate, t *testing.T) *Image {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache bool) *Image {
if srv == nil {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
srv = &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
}
httpServer, err := mkTestingFileServer(context.remoteFiles)
@ -224,10 +226,10 @@ func buildImage(context testContextTemplate, t *testing.T) *Image {
}
port := httpServer.URL[idx+1:]
ip := runtime.networkManager.bridgeNetwork.IP
ip := srv.runtime.networkManager.bridgeNetwork.IP
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := NewBuildFile(srv, ioutil.Discard, false)
buildfile := NewBuildFile(srv, ioutil.Discard, false, useCache)
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
if err != nil {
t.Fatal(err)
@ -245,7 +247,7 @@ func TestVolume(t *testing.T) {
from {IMAGE}
volume /test
cmd Hello world
`, nil, nil}, t)
`, nil, nil}, t, nil, true)
if len(img.Config.Volumes) == 0 {
t.Fail()
@ -261,7 +263,7 @@ func TestBuildMaintainer(t *testing.T) {
img := buildImage(testContextTemplate{`
from {IMAGE}
maintainer dockerio
`, nil, nil}, t)
`, nil, nil}, t, nil, true)
if img.Author != "dockerio" {
t.Fail()
@ -273,7 +275,7 @@ func TestBuildEnv(t *testing.T) {
from {IMAGE}
env port 4243
`,
nil, nil}, t)
nil, nil}, t, nil, true)
hasEnv := false
for _, envVar := range img.Config.Env {
if envVar == "port=4243" {
@ -291,7 +293,7 @@ func TestBuildCmd(t *testing.T) {
from {IMAGE}
cmd ["/bin/echo", "Hello World"]
`,
nil, nil}, t)
nil, nil}, t, nil, true)
if img.Config.Cmd[0] != "/bin/echo" {
t.Log(img.Config.Cmd[0])
@ -308,7 +310,7 @@ func TestBuildExpose(t *testing.T) {
from {IMAGE}
expose 4243
`,
nil, nil}, t)
nil, nil}, t, nil, true)
if img.Config.PortSpecs[0] != "4243" {
t.Fail()
@ -320,8 +322,70 @@ func TestBuildEntrypoint(t *testing.T) {
from {IMAGE}
entrypoint ["/bin/echo"]
`,
nil, nil}, t)
nil, nil}, t, nil, true)
if img.Config.Entrypoint[0] != "/bin/echo" {
}
}
func TestBuildImageWithCache(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
template := testContextTemplate{`
from {IMAGE}
maintainer dockerio
`,
nil, nil}
img := buildImage(template, t, srv, true)
imageId := img.ID
img = nil
img = buildImage(template, t, srv, true)
if imageId != img.ID {
t.Logf("Image ids should match: %s != %s", imageId, img.ID)
t.Fail()
}
}
func TestBuildImageWithoutCache(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
pullingPool: make(map[string]struct{}),
pushingPool: make(map[string]struct{}),
}
template := testContextTemplate{`
from {IMAGE}
maintainer dockerio
`,
nil, nil}
img := buildImage(template, t, srv, true)
imageId := img.ID
img = nil
img = buildImage(template, t, srv, false)
if imageId == img.ID {
t.Logf("Image ids should not match: %s == %s", imageId, img.ID)
t.Fail()
}
}

View file

@ -30,7 +30,8 @@ import (
const VERSION = "0.5.0-dev"
var (
GITCOMMIT string
GITCOMMIT string
AuthRequiredError = fmt.Errorf("Authentication is required.")
)
func (cli *DockerCli) getMethod(name string) (reflect.Method, bool) {
@ -160,6 +161,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
cmd := Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
tag := cmd.String("t", "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
suppressOutput := cmd.Bool("q", false, "Suppress verbose build output")
noCache := cmd.Bool("no-cache", false, "Do not use cache when building the image")
if err := cmd.Parse(args); err != nil {
return nil
}
@ -207,6 +209,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
if isRemote {
v.Set("remote", cmd.Arg(0))
}
if *noCache {
v.Set("nocache", "1")
}
req, err := http.NewRequest("POST", fmt.Sprintf("/v%g/build?%s", APIVERSION, v.Encode()), body)
if err != nil {
return err
@ -447,6 +452,15 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
if out.GoVersion != "" {
fmt.Fprintf(cli.out, "Go version: %s\n", out.GoVersion)
}
release := utils.GetReleaseVersion()
if release != "" {
fmt.Fprintf(cli.out, "Last stable version: %s", release)
if strings.Trim(VERSION, "-dev") != release || strings.Trim(out.Version, "-dev") != release {
fmt.Fprintf(cli.out, ", please update docker")
}
fmt.Fprintf(cli.out, "\n")
}
return nil
}
@ -813,10 +827,6 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return nil
}
if err := cli.checkIfLogged("push"); err != nil {
return err
}
// If we're not using a custom registry, we know the restrictions
// applied to repository names and can warn the user in advance.
// Custom repositories can have different rules, and we must also
@ -825,13 +835,22 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.configFile.Configs[auth.IndexServerAddress()].Username, name)
}
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
if err != nil {
return err
v := url.Values{}
push := func() error {
buf, err := json.Marshal(cli.configFile.Configs[auth.IndexServerAddress()])
if err != nil {
return err
}
return cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out)
}
v := url.Values{}
if err := cli.stream("POST", "/images/"+name+"/push?"+v.Encode(), bytes.NewBuffer(buf), cli.out); err != nil {
if err := push(); err != nil {
if err == AuthRequiredError {
if err = cli.checkIfLogged("push"); err == nil {
return push()
}
}
return err
}
return nil
@ -1558,6 +1577,9 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer) e
} else if err != nil {
return err
}
if jm.Error != nil && jm.Error.Code == 401 {
return AuthRequiredError
}
jm.Display(out)
}
} else {

View file

@ -653,6 +653,7 @@ func (container *Container) Start(hostConfig *HostConfig) error {
"-e", "HOME=/",
"-e", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"-e", "container=lxc",
"-e", "HOSTNAME="+container.Config.Hostname,
)
for _, elem := range container.Config.Env {

View file

@ -960,6 +960,7 @@ func TestEnv(t *testing.T) {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOME=/",
"container=lxc",
"HOSTNAME=" + container.ShortID(),
}
sort.Strings(goodEnv)
if len(goodEnv) != len(actualEnv) {

View file

@ -928,6 +928,7 @@ Build an image from Dockerfile via stdin
: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

View file

@ -12,6 +12,7 @@
Build a new container image from the source code at PATH
-t="": Repository name (and optionally a tag) to be applied to the resulting image in case of success.
-q=false: Suppress verbose build output.
-no-cache: Do not use the cache when building the image.
When a single Dockerfile is given as URL, then no context is set. When a git repository is set as URL, the repository is used as context
@ -28,6 +29,13 @@ Examples
| If the absolute path is provided instead of '.', only the files and directories required by the ADD commands from the Dockerfile will be added to the context and transferred to the docker daemon.
|
.. code-block:: bash
docker build -t vieux/apache:2.0 .
| This will build like the preview example, but it will then tag the resulting image, the repository name will be 'vieux/apache' and the tag will be '2.0'
.. code-block:: bash
docker build - < Dockerfile

View file

@ -15,12 +15,11 @@ In short, Docker has the following kernel requirements:
- Cgroups and namespaces must be enabled.
The officially supported kernel is the one recommended by the
:ref:`ubuntu_linux` installation path. It is the one that most developers
will use, and the one that receives the most attention from the core
contributors. If you decide to go with a different kernel and hit a bug,
please try to reproduce it with the official kernels first.
The officially supported kernel is the one recommended by the
:ref:`ubuntu_linux` installation path. It is the one that most developers
will use, and the one that receives the most attention from the core
contributors. If you decide to go with a different kernel and hit a bug,
please try to reproduce it with the official kernels first.
If you cannot or do not want to use the "official" kernels,
here is some technical background about the features (both optional and

View file

@ -19,6 +19,8 @@ Docker has the following dependencies
* Linux kernel 3.8 (read more about :ref:`kernel`)
* AUFS file system support (we are working on BTRFS support as an alternative)
Please read :ref:`ufw`, if you plan to use `UFW (Uncomplicated Firewall) <https://help.ubuntu.com/community/UFW>`_
.. _ubuntu_precise:
Ubuntu Precise 12.04 (LTS) (64-bit)
@ -135,3 +137,35 @@ Verify it worked
**Done!**, now continue with the :ref:`hello_world` example.
.. _ufw:
Docker and UFW
^^^^^^^^^^^^^^
Docker uses a bridge to manage containers networking, by default UFW drop all `forwarding`, a first step is to enable forwarding:
.. code-block:: bash
sudo nano /etc/default/ufw
----
# Change:
# DEFAULT_FORWARD_POLICY="DROP"
# to
DEFAULT_FORWARD_POLICY="ACCEPT"
Then reload UFW:
.. code-block:: bash
sudo ufw reload
UFW's default set of rules denied all `incoming`, so if you want to be able to reach your containers from another host,
you should allow incoming connexions on the docker port (default 4243):
.. code-block:: bash
sudo ufw allow 4243/tcp

View file

@ -182,7 +182,7 @@ The copy obeys the following rules:
written at ``<dst>``.
* If ``<dest>`` doesn't exist, it is created along with all missing
directories in its path. All new files and directories are created
with mode 0700, uid and gid 0.
with mode 0755, uid and gid 0.
3.8 ENTRYPOINT
--------------

View file

@ -79,7 +79,7 @@
</div>
<div style="margin-left: -12px; float: left;">
<a href="http://www.docker.io" title="Docker Homepage"><img style="margin-top: 0px; height: 60px; margin-left: 10px;" src="{{ pathto('_static/img/docker-top-logo.png', 1) }}"></a>
<a href="http://www.docker.io" title="Docker Homepage"><img style="margin-top: 0px; height: 60px; width: 160px; margin-left: 10px;" src="{{ pathto('_static/img/docker-top-logo.png', 1) }}"></a>
</div>
</div>

View file

@ -147,7 +147,7 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s
res, err := doWithCookies(r.client, req)
if err != nil || res.StatusCode != 200 {
if res != nil {
return nil, fmt.Errorf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
}
return nil, err
}
@ -197,7 +197,7 @@ func (r *Registry) GetRemoteImageJSON(imgID, registry string, token []string) ([
}
defer res.Body.Close()
if res.StatusCode != 200 {
return nil, -1, fmt.Errorf("HTTP code %d", res.StatusCode)
return nil, -1, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
}
imageSize, err := strconv.Atoi(res.Header.Get("X-Docker-Size"))
@ -289,12 +289,12 @@ func (r *Registry) GetRepositoryData(indexEp, remote string) (*RepositoryData, e
}
defer res.Body.Close()
if res.StatusCode == 401 {
return nil, fmt.Errorf("Please login first (HTTP code %d)", res.StatusCode)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Please login first (HTTP code %d)", res.StatusCode), res)
}
// TODO: Right now we're ignoring checksums in the response body.
// In the future, we need to use them to check image validity.
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP code: %d", res.StatusCode)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
}
var tokens []string
@ -391,7 +391,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
return utils.NewHTTPRequestError(fmt.Sprint("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
}
var jsonBody map[string]string
if err := json.Unmarshal(errBody, &jsonBody); err != nil {
@ -399,7 +399,7 @@ func (r *Registry) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, regis
} else if jsonBody["error"] == "Image already exists" {
return ErrAlreadyExists
}
return fmt.Errorf("HTTP code %d while uploading metadata: %s", res.StatusCode, errBody)
return utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata: %s", res.StatusCode, errBody), res)
}
return nil
}
@ -427,9 +427,9 @@ func (r *Registry) PushImageLayerRegistry(imgID string, layer io.Reader, registr
if res.StatusCode != 200 {
errBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return "", fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
return "", utils.NewHTTPRequestError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
}
return "", fmt.Errorf("Received HTTP code %d while uploading layer: %s", res.StatusCode, errBody)
return "", utils.NewHTTPRequestError(fmt.Sprintf("Received HTTP code %d while uploading layer: %s", res.StatusCode, errBody), res)
}
return tarsumLayer.Sum(jsonRaw), nil
}
@ -463,7 +463,7 @@ func (r *Registry) PushRegistryTag(remote, revision, tag, registry string, token
}
res.Body.Close()
if res.StatusCode != 200 && res.StatusCode != 201 {
return fmt.Errorf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote)
return utils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote), res)
}
return nil
}
@ -540,7 +540,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
if err != nil {
return nil, err
}
return nil, fmt.Errorf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %s", res.StatusCode, remote, errBody), res)
}
if res.Header.Get("X-Docker-Token") != "" {
tokens = res.Header["X-Docker-Token"]
@ -564,7 +564,7 @@ func (r *Registry) PushImageJSONIndex(indexEp, remote string, imgList []*ImgData
if err != nil {
return nil, err
}
return nil, fmt.Errorf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %s", res.StatusCode, remote, errBody), res)
}
}
@ -586,7 +586,7 @@ func (r *Registry) SearchRepositories(term string) (*SearchResults, error) {
}
defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("Unexepected status code %d", res.StatusCode)
return nil, utils.NewHTTPRequestError(fmt.Sprintf("Unexepected status code %d", res.StatusCode), res)
}
rawData, err := ioutil.ReadAll(res.Body)
if err != nil {

View file

@ -40,6 +40,10 @@ Deployment
export SMTP_USER=xxxxxxxxxxxx
export SMTP_PWD=xxxxxxxxxxxx
# Define docker registry functional test credentials
export REGISTRY_USER=xxxxxxxxxxxx
export REGISTRY_PWD=xxxxxxxxxxxx
# Checkout docker
git clone git://github.com/dotcloud/docker.git

4
testing/Vagrantfile vendored
View file

@ -29,7 +29,9 @@ Vagrant::Config.run do |config|
"chown #{USER}.#{USER} /data; cd /data; " \
"#{CFG_PATH}/setup.sh #{USER} #{CFG_PATH} #{ENV['BUILDBOT_PWD']} " \
"#{ENV['IRC_PWD']} #{ENV['IRC_CHANNEL']} #{ENV['SMTP_USER']} " \
"#{ENV['SMTP_PWD']} #{ENV['EMAIL_RCP']}; "
"#{ENV['SMTP_PWD']} #{ENV['EMAIL_RCP']}; " \
"#{CFG_PATH}/setup_credentials.sh #{USER} " \
"#{ENV['REGISTRY_USER']} #{ENV['REGISTRY_PWD']}; "
# Install docker dependencies
pkg_cmd << "apt-get install -q -y python-software-properties; " \
"add-apt-repository -y ppa:dotcloud/docker-golang/ubuntu; apt-get update -qq; " \

View file

@ -0,0 +1,5 @@
# Credentials for tests. Buildbot source this file on tests
# when needed.
# Docker registry credentials. Format: 'username:password'
export DOCKER_CREDS=''

View file

@ -19,6 +19,7 @@ TEST_USER = 'buildbot' # Credential to authenticate build triggers
TEST_PWD = 'docker' # Credential to authenticate build triggers
BUILDER_NAME = 'docker'
GITHUB_DOCKER = 'github.com/dotcloud/docker'
BUILDBOT_PATH = '/data/buildbot'
DOCKER_PATH = '/data/docker'
BUILDER_PATH = '/data/buildbot/slave/{0}/build'.format(BUILDER_NAME)
DOCKER_BUILD_PATH = BUILDER_PATH + '/src/github.com/dotcloud/docker'
@ -41,16 +42,19 @@ c['db'] = {'db_url':"sqlite:///state.sqlite"}
c['slaves'] = [BuildSlave('buildworker', BUILDBOT_PWD)]
c['slavePortnum'] = PORT_MASTER
# Schedulers
c['schedulers'] = [ForceScheduler(name='trigger', builderNames=[BUILDER_NAME,
'coverage'])]
'registry','coverage'])]
c['schedulers'] += [SingleBranchScheduler(name="all",
change_filter=filter.ChangeFilter(branch='master'), treeStableTimer=None,
builderNames=[BUILDER_NAME])]
c['schedulers'] += [Nightly(name='daily', branch=None, builderNames=['coverage'],
c['schedulers'] += [Nightly(name='daily', branch=None, builderNames=['coverage','registry'],
hour=0, minute=30)]
# Builders
# Docker commit test
factory = BuildFactory()
factory.addStep(ShellCommand(description='Docker',logEnviron=False,usePTY=True,
command=["sh", "-c", Interpolate("cd ..; rm -rf build; export GOPATH={0}; "
@ -58,6 +62,7 @@ factory.addStep(ShellCommand(description='Docker',logEnviron=False,usePTY=True,
"go test -v".format(BUILDER_PATH,GITHUB_DOCKER,DOCKER_BUILD_PATH))]))
c['builders'] = [BuilderConfig(name=BUILDER_NAME,slavenames=['buildworker'],
factory=factory)]
# Docker coverage test
coverage_cmd = ('GOPATH=`pwd` go get -d github.com/dotcloud/docker\n'
'GOPATH=`pwd` go get github.com/axw/gocov/gocov\n'
@ -69,6 +74,17 @@ factory.addStep(ShellCommand(description='Coverage',logEnviron=False,usePTY=True
c['builders'] += [BuilderConfig(name='coverage',slavenames=['buildworker'],
factory=factory)]
# Registry Functionaltest builder
factory = BuildFactory()
factory.addStep(ShellCommand(description='registry', logEnviron=False,
command='. {0}/master/credentials.cfg; '
'{1}/testing/functionaltests/test_registry.sh'.format(BUILDBOT_PATH,
DOCKER_PATH), usePTY=True))
c['builders'] += [BuilderConfig(name='registry',slavenames=['buildworker'],
factory=factory)]
# Status
authz_cfg = authz.Authz(auth=auth.BasicAuth([(TEST_USER, TEST_PWD)]),
forceBuild='auth')

View file

@ -4,3 +4,4 @@ buildbot==0.8.7p1
buildbot_slave==0.8.7p1
nose==1.2.1
requests==1.1.0
flask==0.10.1

View file

@ -0,0 +1,17 @@
#!/bin/bash
# Setup of test credentials. Called by Vagrantfile
export PATH="/bin:sbin:/usr/bin:/usr/sbin:/usr/local/bin"
USER=$1
REGISTRY_USER=$2
REGISTRY_PWD=$3
BUILDBOT_PATH="/data/buildbot"
DOCKER_PATH="/data/docker"
function run { su $USER -c "$1"; }
run "cp $DOCKER_PATH/testing/buildbot/credentials.cfg $BUILDBOT_PATH/master"
cd $BUILDBOT_PATH/master
run "sed -i -E 's#(export DOCKER_CREDS=).+#\1\"$REGISTRY_USER:$REGISTRY_PWD\"#' credentials.cfg"

View file

@ -0,0 +1,11 @@
#!/bin/sh
# Cleanup
rm -rf docker-registry
# Get latest docker registry
git clone https://github.com/dotcloud/docker-registry.git
# Configure and run registry tests
cd docker-registry; cp config_sample.yml config.yml
cd test; python -m unittest workflow

View file

@ -607,12 +607,29 @@ func NewWriteFlusher(w io.Writer) *WriteFlusher {
return &WriteFlusher{w: w, flusher: flusher}
}
type JSONError struct {
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
}
type JSONMessage struct {
Status string `json:"status,omitempty"`
Progress string `json:"progress,omitempty"`
Error string `json:"error,omitempty"`
ID string `json:"id,omitempty"`
Time int64 `json:"time,omitempty"`
Status string `json:"status,omitempty"`
Progress string `json:"progress,omitempty"`
ErrorMessage string `json:"error,omitempty"` //deprecated
ID string `json:"id,omitempty"`
Time int64 `json:"time,omitempty"`
Error *JSONError `json:"errorDetail,omitempty"`
}
func (e *JSONError) Error() string {
return e.Message
}
func NewHTTPRequestError(msg string, res *http.Response) error {
return &JSONError{
Message: msg,
Code: res.StatusCode,
}
}
func (jm *JSONMessage) Display(out io.Writer) error {
@ -621,8 +638,8 @@ func (jm *JSONMessage) Display(out io.Writer) error {
}
if jm.Progress != "" {
fmt.Fprintf(out, "%s %s\r", jm.Status, jm.Progress)
} else if jm.Error != "" {
return fmt.Errorf(jm.Error)
} else if jm.Error != nil {
return jm.Error
} else if jm.ID != "" {
fmt.Fprintf(out, "%s: %s\n", jm.ID, jm.Status)
} else {
@ -656,7 +673,11 @@ func (sf *StreamFormatter) FormatStatus(format string, a ...interface{}) []byte
func (sf *StreamFormatter) FormatError(err error) []byte {
sf.used = true
if sf.json {
if b, err := json.Marshal(&JSONMessage{Error: err.Error()}); err == nil {
jsonError, ok := err.(*JSONError)
if !ok {
jsonError = &JSONError{Message: err.Error()}
}
if b, err := json.Marshal(&JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil {
return b
}
return []byte("{\"error\":\"format error\"}")
@ -688,17 +709,29 @@ func IsGIT(str string) bool {
return strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "github.com/")
}
func CheckLocalDns() bool {
// GetResolvConf opens and read the content of /etc/resolv.conf.
// It returns it as byte slice.
func GetResolvConf() ([]byte, error) {
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
Debugf("Error openning resolv.conf: %s", err)
return false
return nil, err
}
for _, ip := range []string{
"127.0.0.1",
"127.0.1.1",
return resolv, nil
}
// CheckLocalDns looks into the /etc/resolv.conf,
// it returns true if there is a local nameserver or if there is no nameserver.
func CheckLocalDns(resolvConf []byte) bool {
if !bytes.Contains(resolvConf, []byte("nameserver")) {
return true
}
for _, ip := range [][]byte{
[]byte("127.0.0.1"),
[]byte("127.0.1.1"),
} {
if strings.Contains(string(resolv), ip) {
if bytes.Contains(resolvConf, ip) {
return true
}
}
@ -730,6 +763,22 @@ func ParseHost(host string, port int, addr string) string {
return fmt.Sprintf("tcp://%s:%d", host, port)
}
func GetReleaseVersion() string {
resp, err := http.Get("http://get.docker.io/latest")
if err != nil {
return ""
}
defer resp.Body.Close()
if resp.ContentLength > 24 || resp.StatusCode != 200 {
return ""
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ""
}
return strings.TrimSpace(string(body))
}
// Get a repos name and returns the right reposName + tag
// The tag can be confusing because of a port in a repository name.
// Ex: localhost.localdomain:5000/samalba/hipache:latest

View file

@ -303,3 +303,37 @@ func TestParseRepositoryTag(t *testing.T) {
t.Errorf("Expected repo: '%s' and tag: '%s', got '%s' and '%s'", "url:5000/repo", "tag", repo, tag)
}
}
func TestGetResolvConf(t *testing.T) {
resolvConfUtils, err := GetResolvConf()
if err != nil {
t.Fatal(err)
}
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
t.Fatal(err)
}
if string(resolvConfUtils) != string(resolvConfSystem) {
t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.")
}
}
func TestCheclLocalDns(t *testing.T) {
for resolv, result := range map[string]bool{`# Dynamic
nameserver 10.0.2.3
search dotcloud.net`: false,
`# Dynamic
nameserver 127.0.0.1
search dotcloud.net`: true,
`# Dynamic
nameserver 127.0.1.1
search dotcloud.net`: true,
`# Dynamic
`: true,
``: true,
} {
if CheckLocalDns([]byte(resolv)) != result {
t.Fatalf("Wrong local dns detection: {%s} should be %v", resolv, result)
}
}
}

View file

@ -191,7 +191,7 @@ func TestMergeConfig(t *testing.T) {
if len(configUser.Volumes) != 3 {
t.Fatalf("Expected 3 volumes, /test1, /test2 and /test3, found %d", len(configUser.Volumes))
}
for v, _ := range 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)
}