Compare commits

..

1 Commits

Author SHA1 Message Date
David Calavera 4f1c66a50e Bump version to 1.8.0
Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit d9f7fd9493e42d34a4be640a8c24781b8d7b4726)
2015-07-24 20:28:37 -07:00
959 changed files with 21966 additions and 33293 deletions
+4 -17
View File
@@ -1,12 +1,6 @@
# Changelog
## 1.8.1 (2015-08-12)
### Distribution
* Fix a bug where pushing multiple tags would result in invalid images
## 1.8.0 (2015-08-11)
## 1.8.0 (2015-07-24)
### Distribution
@@ -42,7 +36,7 @@
+ Add logging driver for GELF via UDP
+ Allow to copy files from host to containers with `docker cp`
+ Promote volume drivers from experimental to master
+ Add rollover options to json-file log driver, and --log-driver-opts flag
+ Add rollover log driver, and --log-driver-opts flag
+ Add memory swappiness tuning options
* Remove cgroup read-only flag when privileged
* Make /proc, /sys, & /dev readonly for readonly containers
@@ -53,7 +47,7 @@
* Remove RC4 from the list of registry cipher suites
* Add syslog-facility option
* LXC execdriver compatibility with recent LXC versions
* Mark LXC execriver as deprecated (to be removed with the migration to runc)
### Plugins
@@ -63,7 +57,7 @@
### Bug fixes
- Add missing 'Names' field to /containers/json API output
- Make `docker rmi` of dangling images safe while pulling
- Make `docker rmi --dangling` safe when pulling
- Devicemapper: Change default basesize to 100G
- Go Scheduler issue with sync.Mutex and gcc
- Fix issue where Search API endpoint would panic due to empty AuthConfig
@@ -89,13 +83,6 @@
- Remove panic in nat package on invalid hostport
- Fix container linking in Fedora 22
- Fix error caused using default gateways outside of the allocated range
- Format times in inspect command with a template as RFC3339Nano
- Make registry client to accept 2xx and 3xx http status responses as successful
- Fix race issue that caused the daemon to crash with certain layer downloads failed in a specific order.
- Fix error when the docker ps format was not valid.
- Remove redundant ip forward check.
- Fix issue trying to push images to repository mirrors.
- Fix error cleaning up network entrypoints when there is an initialization issue.
## 1.7.1 (2015-07-14)
+3 -4
View File
@@ -40,7 +40,6 @@ RUN apt-get update && apt-get install -y \
createrepo \
curl \
dpkg-sig \
gcc-mingw-w64 \
git \
iptables \
libapparmor-dev \
@@ -128,7 +127,7 @@ RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint
RUN gem install --no-rdoc --no-ri fpm --version 1.3.2
# Install registry
ENV REGISTRY_COMMIT ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT 2317f721a3d8428215a2b65da4ae85212ed473b4
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
@@ -138,7 +137,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_COMMIT 8e8122eb5528f621afcd4e2854c47302f17392f7
ENV NOTARY_COMMIT 77bced079e83d80f40c1f0a544b1a8a3b97fb052
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
@@ -148,7 +147,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT 139850f3f3b17357bab5ba3edfb745fb14043764
ENV DOCKER_PY_COMMIT 8a87001d09852058f08a807ab6e8491d57ca1e88
RUN git clone https://github.com/docker/docker-py.git /docker-py \
&& cd /docker-py \
&& git checkout -q $DOCKER_PY_COMMIT
+1 -1
View File
@@ -309,7 +309,7 @@ made through a pull request.
# - If the pull request has some small problems that need to be changed, make
# a comment adressing the issues.
# - If the changes needed to a PR are small, you can add a "LGTM once the
# following comments are addressed..." this will reduce needless back and
# following comments are adressed..." this will reduce needless back and
# forth.
# - If the PR only needs a few changes before being merged, any MAINTAINER can
# make a replacement PR that incorporates the existing commits and fixes the
+9 -14
View File
@@ -1,19 +1,19 @@
Docker: the container engine [![Release](https://img.shields.io/github/release/docker/docker.svg)](https://github.com/docker/docker/releases/latest)
============================
Docker: the Linux container engine
==================================
Docker is an open source project to pack, ship and run any application
as a lightweight container.
Docker containers are both *hardware-agnostic* and *platform-agnostic*.
This means they can run anywhere, from your laptop to the largest
cloud compute instance and everything in between - and they don't require
EC2 compute instance and everything in between - and they don't require
you to use a particular language, framework or packaging system. That
makes them great building blocks for deploying and scaling web apps,
databases, and backend services without depending on a particular stack
or provider.
Docker began as an open-source implementation of the deployment engine which
powers [dotCloud](https://www.dotcloud.com), a popular Platform-as-a-Service.
powers [dotCloud](https://dotcloud.com), a popular Platform-as-a-Service.
It benefits directly from the experience accumulated over several years
of large-scale operation and support of hundreds of thousands of
applications and databases.
@@ -174,14 +174,13 @@ Under the hood, Docker is built on the following components:
capabilities of the Linux kernel
* The [Go](https://golang.org) programming language
* The [Docker Image Specification](https://github.com/docker/docker/blob/master/image/spec/v1.md)
* The [Libcontainer Specification](https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md)
* The [Libcontainer Specification](https://github.com/docker/libcontainer/blob/master/SPEC.md)
Contributing to Docker [![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker)
Contributing to Docker
======================
| **Master** (Linux) | **Experimental** (linux) | **Windows** | **FreeBSD** |
|------------------|----------------------|---------|---------|
| [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master/) | [![Jenkins Build Status](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/badge/icon)](https://jenkins.dockerproject.org/view/Docker/job/Docker%20Master%20%28experimental%29/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(windows)/) | [![Build Status](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/badge/icon)](http://jenkins.dockerproject.org/job/Docker%20Master%20(freebsd)/) |
[![GoDoc](https://godoc.org/github.com/docker/docker?status.svg)](https://godoc.org/github.com/docker/docker)
[![Jenkins Build Status](https://jenkins.dockerproject.org/job/Docker%20Master/badge/icon)](https://jenkins.dockerproject.org/job/Docker%20Master/)
Want to hack on Docker? Awesome! We have [instructions to help you get
started contributing code or documentation](https://docs.docker.com/project/who-written-for/).
@@ -248,7 +247,7 @@ We are always open to suggestions on process improvements, and are always lookin
<tr>
<td>Stack Overflow</td>
<td>
Stack Overflow has over 7000 Docker questions listed. We regularly
Stack Overflow has over 7000K Docker questions listed. We regularly
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
and so do many other knowledgeable Docker users.
</td>
@@ -294,7 +293,3 @@ Docker on Mac and Windows
If you know of another project underway that should be listed here, please help
us keep this list up-to-date by submitting a PR.
Awesome-Docker
==============
You can find more projects, tools and articles related to Docker on the [awesome-docker list](https://github.com/veggiemonk/awesome-docker). Add your project there.
+1 -1
View File
@@ -134,7 +134,7 @@ We won't accept patches expanding the surface of `docker exec`, which we intend
## 2.2 Dockerfile syntax
The Dockerfile syntax as we know it is simple, and has proven successful in supporting all our
The Dockerfile syntax as we know it is simple, and has proven succesful in supporting all our
[official images](https://github.com/docker-library/official-images). Although this is *not* a
definitive move, we temporarily won't accept more patches to the Dockerfile syntax for several
reasons:
+1 -1
View File
@@ -1 +1 @@
1.9.0-dev
1.8.0-rc1
+19
View File
@@ -0,0 +1,19 @@
package api
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()
}
}
+24 -95
View File
@@ -31,6 +31,7 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/units"
"github.com/docker/docker/pkg/urlutil"
@@ -59,8 +60,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
flCPUShares := cmd.Int64([]string{"c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flCpuPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
flCpuQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
@@ -114,9 +115,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
}
// Resolve the FROM lines in the Dockerfile to trusted digest references
// using Notary. On a successful build, we must tag the resolved digests
// to the original name specified in the Dockerfile.
newDockerfile, resolvedTags, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference)
// using Notary.
newDockerfile, err := rewriteDockerfileFrom(filepath.Join(contextDir, relDockerfile), cli.trustedReference)
if err != nil {
return fmt.Errorf("unable to process Dockerfile: %v", err)
}
@@ -242,8 +242,8 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
v.Set("cpusetcpus", *flCPUSetCpus)
v.Set("cpusetmems", *flCPUSetMems)
v.Set("cpushares", strconv.FormatInt(*flCPUShares, 10))
v.Set("cpuquota", strconv.FormatInt(*flCPUQuota, 10))
v.Set("cpuperiod", strconv.FormatInt(*flCPUPeriod, 10))
v.Set("cpuquota", strconv.FormatInt(*flCpuQuota, 10))
v.Set("cpuperiod", strconv.FormatInt(*flCpuPeriod, 10))
v.Set("memory", strconv.FormatInt(memory, 10))
v.Set("memswap", strconv.FormatInt(memorySwap, 10))
v.Set("cgroupparent", *flCgroupParent)
@@ -251,11 +251,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
v.Set("dockerfile", relDockerfile)
ulimitsVar := flUlimits.GetList()
ulimitsJSON, err := json.Marshal(ulimitsVar)
ulimitsJson, err := json.Marshal(ulimitsVar)
if err != nil {
return err
}
v.Set("ulimits", string(ulimitsJSON))
v.Set("ulimits", string(ulimitsJson))
headers := http.Header(make(map[string][]string))
buf, err := json.Marshal(cli.configFile.AuthConfigs)
@@ -291,26 +291,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
}
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
}
if err != nil {
return err
}
// Since the build was successful, now we must tag any of the resolved
// images from the above Dockerfile rewrite.
for _, resolved := range resolvedTags {
if err := cli.tagTrusted(resolved.repoInfo, resolved.digestRef, resolved.tagRef); err != nil {
return err
}
}
return nil
}
// isUNC returns true if the path is UNC (one starting \\). It always returns
// false on Linux.
func isUNC(path string) bool {
return runtime.GOOS == "windows" && strings.HasPrefix(path, `\\`)
return err
}
// getDockerfileRelPath uses the given context directory for a `docker build`
@@ -321,29 +302,6 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
return "", "", fmt.Errorf("unable to get absolute context directory: %v", err)
}
// The context dir might be a symbolic link, so follow it to the actual
// target directory.
//
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
// paths (those starting with \\). This hack means that when using links
// on UNC paths, they will not be followed.
if !isUNC(absContextDir) {
absContextDir, err = filepath.EvalSymlinks(absContextDir)
if err != nil {
return "", "", fmt.Errorf("unable to evaluate symlinks in context path: %v", err)
}
}
stat, err := os.Lstat(absContextDir)
if err != nil {
return "", "", fmt.Errorf("unable to stat context directory %q: %v", absContextDir, err)
}
if !stat.IsDir() {
return "", "", fmt.Errorf("context must be a directory: %s", absContextDir)
}
absDockerfile := givenDockerfile
if absDockerfile == "" {
// No -f/--file was specified so use the default relative to the
@@ -366,22 +324,15 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
absDockerfile = filepath.Join(absContextDir, absDockerfile)
}
// Evaluate symlinks in the path to the Dockerfile too.
//
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
// paths (those starting with \\). This hack means that when using links
// on UNC paths, they will not be followed.
if !isUNC(absDockerfile) {
absDockerfile, err = filepath.EvalSymlinks(absDockerfile)
if err != nil {
return "", "", fmt.Errorf("unable to evaluate symlinks in Dockerfile path: %v", err)
}
// Verify that 'filename' is within the build context
absDockerfile, err = symlink.FollowSymlinkInScope(absDockerfile, absContextDir)
if err != nil {
return "", "", fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", givenDockerfile, givenContextDir)
}
if _, err := os.Lstat(absDockerfile); err != nil {
if os.IsNotExist(err) {
return "", "", fmt.Errorf("Cannot locate Dockerfile: %q", absDockerfile)
return "", "", fmt.Errorf("Cannot locate Dockerfile: absDockerfile: %q", absDockerfile)
}
return "", "", fmt.Errorf("unable to stat Dockerfile: %v", err)
}
@@ -390,10 +341,6 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi
return "", "", fmt.Errorf("unable to get relative Dockerfile path: %v", err)
}
if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
return "", "", fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", givenDockerfile, givenContextDir)
}
return absContextDir, relDockerfile, nil
}
@@ -445,7 +392,7 @@ func getContextFromReader(r io.Reader, dockerfileName string) (absContextDir, re
}
if err := archive.Untar(buf, absContextDir, nil); err != nil {
return "", "", fmt.Errorf("unable to extract stdin to temporary context directory: %v", err)
return "", "", fmt.Errorf("unable to extract stdin to temporary context direcotry: %v", err)
}
return getDockerfileRelPath(absContextDir, dockerfileName)
@@ -482,7 +429,7 @@ func getContextFromURL(out io.Writer, remoteURL, dockerfileName string) (absCont
In: response.Body,
Out: out,
Formatter: streamformatter.NewStreamFormatter(),
Size: response.ContentLength,
Size: int(response.ContentLength),
NewLines: true,
ID: "",
Action: fmt.Sprintf("Downloading build context from remote url: %s", remoteURL),
@@ -520,21 +467,14 @@ func (td *trustedDockerfile) Close() error {
return os.Remove(td.File.Name())
}
// resolvedTag records the repository, tag, and resolved digest reference
// from a Dockerfile rewrite.
type resolvedTag struct {
repoInfo *registry.RepositoryInfo
digestRef, tagRef registry.Reference
}
// rewriteDockerfileFrom rewrites the given Dockerfile by resolving images in
// "FROM <image>" instructions to a digest reference. `translator` is a
// function that takes a repository name and tag reference and returns a
// trusted digest reference.
func rewriteDockerfileFrom(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, resolvedTags []*resolvedTag, err error) {
func rewriteDockerfileFrom(dockerfileName string, translator func(string, registry.Reference) (registry.Reference, error)) (newDockerfile *trustedDockerfile, err error) {
dockerfile, err := os.Open(dockerfileName)
if err != nil {
return nil, nil, fmt.Errorf("unable to open Dockerfile: %v", err)
return nil, fmt.Errorf("unable to open Dockerfile: %v", err)
}
defer dockerfile.Close()
@@ -543,7 +483,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
// Make a tempfile to store the rewritten Dockerfile.
tempFile, err := ioutil.TempFile("", "trusted-dockerfile-")
if err != nil {
return nil, nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
return nil, fmt.Errorf("unable to make temporary trusted Dockerfile: %v", err)
}
trustedFile := &trustedDockerfile{
@@ -567,34 +507,23 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
// Replace the line with a resolved "FROM repo@digest"
repo, tag := parsers.ParseRepositoryTag(matches[1])
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
repoInfo, err := registry.ParseRepositoryInfo(repo)
if err != nil {
return nil, nil, fmt.Errorf("unable to parse repository info: %v", err)
}
ref := registry.ParseReference(tag)
if !ref.HasDigest() && isTrusted() {
trustedRef, err := translator(repo, ref)
if err != nil {
return nil, nil, err
return nil, err
}
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.ImageName(repo)))
resolvedTags = append(resolvedTags, &resolvedTag{
repoInfo: repoInfo,
digestRef: trustedRef,
tagRef: ref,
})
}
}
n, err := fmt.Fprintln(tempFile, line)
if err != nil {
return nil, nil, err
return nil, err
}
trustedFile.size += int64(n)
@@ -602,7 +531,7 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(string, regist
tempFile.Seek(0, os.SEEK_SET)
return trustedFile, resolvedTags, scanner.Err()
return trustedFile, scanner.Err()
}
// replaceDockerfileTarWrapper wraps the given input tar archive stream and
-5
View File
@@ -58,8 +58,6 @@ type DockerCli struct {
transport *http.Transport
}
// Initialize calls the init function that will setup the configuration for the client
// such as the TLS, tcp and other parameters used to run the client.
func (cli *DockerCli) Initialize() error {
if cli.init == nil {
return nil
@@ -79,8 +77,6 @@ func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error {
return nil
}
// PsFormat returns the format string specified in the configuration.
// String contains columns and format specification, for example {{ID}\t{{Name}}.
func (cli *DockerCli) PsFormat() string {
return cli.configFile.PsFormat
}
@@ -98,7 +94,6 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF
}
cli.init = func() error {
clientFlags.PostParse()
hosts := clientFlags.Common.Hosts
+11 -31
View File
@@ -15,7 +15,6 @@ import (
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/pkg/archive"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/system"
)
type copyDirection int
@@ -102,7 +101,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
// client, a `:` could be part of an absolute Windows path, in which case it
// is immediately proceeded by a backslash.
func splitCpArg(arg string) (container, path string) {
if system.IsAbs(arg) {
if filepath.IsAbs(arg) {
// Explicit local absolute path, e.g., `C:\foo` or `/foo`.
return "", arg
}
@@ -233,20 +232,6 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string) (er
// Prepare destination copy info by stat-ing the container path.
dstInfo := archive.CopyInfo{Path: dstPath}
dstStat, err := cli.statContainerPath(dstContainer, dstPath)
// If the destination is a symbolic link, we should evaluate it.
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
linkTarget := dstStat.LinkTarget
if !system.IsAbs(linkTarget) {
// Join with the parent directory.
dstParent, _ := archive.SplitPathDirEntry(dstPath)
linkTarget = filepath.Join(dstParent, linkTarget)
}
dstInfo.Path = linkTarget
dstStat, err = cli.statContainerPath(dstContainer, linkTarget)
}
// Ignore any error and assume that the parent directory of the destination
// path exists, in which case the copy may still succeed. If there is any
// type of conflict (e.g., non-directory overwriting an existing directory
@@ -257,26 +242,15 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string) (er
dstInfo.Exists, dstInfo.IsDir = true, dstStat.Mode.IsDir()
}
var (
content io.Reader
resolvedDstPath string
)
var content io.Reader
if srcPath == "-" {
// Use STDIN.
content = os.Stdin
resolvedDstPath = dstInfo.Path
if !dstInfo.IsDir {
return fmt.Errorf("destination %q must be a directory", fmt.Sprintf("%s:%s", dstContainer, dstPath))
}
} else {
// Prepare source copy info.
srcInfo, err := archive.CopyInfoSourcePath(srcPath)
if err != nil {
return err
}
srcArchive, err := archive.TarResource(srcInfo)
srcArchive, err := archive.TarResource(srcPath)
if err != nil {
return err
}
@@ -288,6 +262,12 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string) (er
// it to the specified directory in the container we get the disired
// copy behavior.
// Prepare source copy info.
srcInfo, err := archive.CopyInfoStatPath(srcPath, true)
if err != nil {
return err
}
// See comments in the implementation of `archive.PrepareArchiveCopy`
// for exactly what goes into deciding how and whether the source
// archive needs to be altered for the correct copy behavior when it is
@@ -300,12 +280,12 @@ func (cli *DockerCli) copyToContainer(srcPath, dstContainer, dstPath string) (er
}
defer preparedArchive.Close()
resolvedDstPath = dstDir
dstPath = dstDir
content = preparedArchive
}
query := make(url.Values, 2)
query.Set("path", filepath.ToSlash(resolvedDstPath)) // Normalize the paths used in the API.
query.Set("path", filepath.ToSlash(dstPath)) // Normalize the paths used in the API.
// Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
query.Set("noOverwriteDirNonDir", "true")
+2 -2
View File
@@ -26,7 +26,7 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
repos, tag := parsers.ParseRepositoryTag(image)
// pull only the image tagged 'latest' if no tag was specified
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
v.Set("fromImage", repos)
v.Set("tag", tag)
@@ -96,7 +96,7 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
repo, tag := parsers.ParseRepositoryTag(config.Image)
if tag == "" {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
}
ref := registry.ParseReference(tag)
+2 -1
View File
@@ -2,6 +2,7 @@ package client
import (
"errors"
"io"
"os"
Cli "github.com/docker/docker/cli"
@@ -21,7 +22,7 @@ func (cli *DockerCli) CmdExport(args ...string) error {
cmd.ParseFlags(args, true)
var (
output = cli.out
output io.Writer = cli.out
err error
)
if *outfile != "" {
+1 -1
View File
@@ -167,7 +167,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
}
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
return fmt.Errorf("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
}
return err
}
+1 -1
View File
@@ -22,7 +22,7 @@ import (
//
// Usage: docker images [OPTIONS] [REPOSITORY]
func (cli *DockerCli) CmdImages(args ...string) error {
cmd := Cli.Subcmd("images", []string{"[REPOSITORY[:TAG]]"}, "List images", true)
cmd := Cli.Subcmd("images", []string{"[REPOSITORY]"}, "List images", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Don't truncate output")
-2
View File
@@ -23,7 +23,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
cmd := Cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, "Create an empty filesystem image and import the contents of the\ntarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then\noptionally tag it.", true)
flChanges := opts.NewListOpts(nil)
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
message := cmd.String([]string{"m", "-message"}, "", "Set commit message for imported image")
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
@@ -36,7 +35,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
v.Set("fromSrc", src)
v.Set("repo", repository)
v.Set("message", *message)
for _, change := range flChanges.GetAll() {
v.Add("changes", change)
}
+4 -4
View File
@@ -61,8 +61,8 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir)
}
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HttpProxy)
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HttpsProxy)
ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
if info.IndexServerAddress != "" {
@@ -82,12 +82,12 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.err, "WARNING: No swap limit support\n")
}
if !info.IPv4Forwarding {
fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled\n")
fmt.Fprintf(cli.err, "WARNING: IPv4 forwarding is disabled.\n")
}
if !info.BridgeNfIptables {
fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-iptables is disabled\n")
}
if !info.BridgeNfIP6tables {
if !info.BridgeNfIp6tables {
fmt.Fprintf(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled\n")
}
}
+6 -7
View File
@@ -26,14 +26,13 @@ func (cli *DockerCli) CmdLogout(args ...string) error {
if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {
fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
return nil
}
} else {
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
delete(cli.configFile.AuthConfigs, serverAddress)
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
delete(cli.configFile.AuthConfigs, serverAddress)
if err := cli.configFile.Save(); err != nil {
return fmt.Errorf("Failed to save docker config: %v", err)
if err := cli.configFile.Save(); err != nil {
return fmt.Errorf("Failed to save docker config: %v", err)
}
}
return nil
}
-1
View File
@@ -8,7 +8,6 @@ import (
nwclient "github.com/docker/libnetwork/client"
)
// CmdNetwork is used to create, display and configure network endpoints.
func (cli *DockerCli) CmdNetwork(args ...string) error {
nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
args = append([]string{"network"}, args...)
+1 -1
View File
@@ -95,7 +95,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
f := *format
if len(f) == 0 {
if len(cli.PsFormat()) > 0 && !*quiet {
if len(cli.PsFormat()) > 0 {
f = cli.PsFormat()
} else {
f = "table"
+4 -10
View File
@@ -64,9 +64,6 @@ func (c *containerContext) Image() string {
if c.c.Image == "" {
return "<no image>"
}
if c.trunc {
return stringutils.Truncate(c.c.Image, 12)
}
return c.c.Image
}
@@ -173,11 +170,9 @@ func customFormat(ctx Context, containers []types.Container) {
format += "\t{{.Size}}"
}
tmpl, err := template.New("").Parse(format)
tmpl, err := template.New("ps template").Parse(format)
if err != nil {
buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err))
buffer.WriteTo(ctx.Output)
return
buffer.WriteString(fmt.Sprintf("Invalid `docker ps` format: %v\n", err))
}
for _, container := range containers {
@@ -186,9 +181,8 @@ func customFormat(ctx Context, containers []types.Container) {
c: container,
}
if err := tmpl.Execute(buffer, containerCtx); err != nil {
buffer = bytes.NewBufferString(fmt.Sprintf("Template parsing error: %v\n", err))
buffer.WriteTo(ctx.Output)
return
buffer = bytes.NewBufferString(fmt.Sprintf("Invalid `docker ps` format: %v\n", err))
break
}
if table && len(header) == 0 {
header = containerCtx.fullHeader()
+4 -18
View File
@@ -1,7 +1,6 @@
package ps
import (
"bytes"
"reflect"
"strings"
"testing"
@@ -11,8 +10,8 @@ import (
"github.com/docker/docker/pkg/stringid"
)
func TestContainerPsContext(t *testing.T) {
containerID := stringid.GenerateRandomID()
func TestContainerContextID(t *testing.T) {
containerId := stringid.GenerateRandomID()
unix := time.Now().Unix()
var ctx containerContext
@@ -23,12 +22,12 @@ func TestContainerPsContext(t *testing.T) {
expHeader string
call func() string
}{
{types.Container{ID: containerID}, true, stringid.TruncateID(containerID), idHeader, ctx.ID},
{types.Container{ID: containerId}, true, stringid.TruncateID(containerId), idHeader, ctx.ID},
{types.Container{Names: []string{"/foobar_baz"}}, true, "foobar_baz", namesHeader, ctx.Names},
{types.Container{Image: "ubuntu"}, true, "ubuntu", imageHeader, ctx.Image},
{types.Container{Image: ""}, true, "<no image>", imageHeader, ctx.Image},
{types.Container{Command: "sh -c 'ls -la'"}, true, `"sh -c 'ls -la'"`, commandHeader, ctx.Command},
{types.Container{Created: unix}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
{types.Container{Created: int(unix)}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
{types.Container{Ports: []types.Port{{PrivatePort: 8080, PublicPort: 8080, Type: "tcp"}}}, true, "8080/tcp", portsHeader, ctx.Ports},
{types.Container{Status: "RUNNING"}, true, "RUNNING", statusHeader, ctx.Status},
{types.Container{SizeRw: 10}, true, "10 B", sizeHeader, ctx.Size},
@@ -87,16 +86,3 @@ func TestContainerPsContext(t *testing.T) {
}
}
func TestContainerPsFormatError(t *testing.T) {
out := bytes.NewBufferString("")
ctx := Context{
Format: "{{InvalidFunction}}",
Output: out,
}
customFormat(ctx, make([]types.Container, 0))
if out.String() != "Template parsing error: template: :1: function \"InvalidFunction\" not defined\n" {
t.Fatalf("Expected format error, got `%v`\n", out.String())
}
}
+3 -11
View File
@@ -14,22 +14,14 @@ const (
defaultQuietFormat = "{{.ID}}"
)
// Context contains information required by the formatter to print the output as desired.
type Context struct {
// Output is the output stream to which the formatted string is written.
Output io.Writer
// Format is used to choose raw, table or custom format for the output.
Format string
// Size when set to true will display the size of the output.
Size bool
// Quiet when set to true will simply print minimal information.
Quiet bool
// Trunc when set to true will truncate the output of certain fields such as Container ID.
Trunc bool
Size bool
Quiet bool
Trunc bool
}
// Format helps to format the output using the parameters set in the Context.
// Currently Format allow to display in raw, table or custom format the output.
func Format(ctx Context, containers []types.Container) {
switch ctx.Format {
case tableFormatKey:
+1 -1
View File
@@ -25,7 +25,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
taglessRemote, tag := parsers.ParseRepositoryTag(remote)
if tag == "" && !*allTags {
tag = tags.DefaultTag
tag = tags.DEFAULTTAG
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
} else if tag != "" && *allTags {
return fmt.Errorf("tag can't be used with --all-tags/-a")
+1 -1
View File
@@ -11,7 +11,7 @@ import (
// CmdRestart restarts one or more running containers.
//
// Usage: docker restart [OPTIONS] CONTAINER [CONTAINER...]
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdRestart(args ...string) error {
cmd := Cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, "Restart a running container", true)
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
+2 -2
View File
@@ -63,11 +63,11 @@ func (cli *DockerCli) CmdRun(args ...string) error {
os.Exit(1)
}
if len(hostConfig.DNS) > 0 {
if len(hostConfig.Dns) > 0 {
// check the DNS settings passed via --dns against
// localhost regexp to warn if they are trying to
// set a DNS to a localhost address
for _, dnsIP := range hostConfig.DNS {
for _, dnsIP := range hostConfig.Dns {
if dns.IsLocalhost(dnsIP) {
fmt.Fprintf(cli.err, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP)
break
+3 -2
View File
@@ -2,6 +2,7 @@ package client
import (
"errors"
"io"
"net/url"
"os"
@@ -16,13 +17,13 @@ import (
// Usage: docker save [OPTIONS] IMAGE [IMAGE...]
func (cli *DockerCli) CmdSave(args ...string) error {
cmd := Cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, "Save an image(s) to a tar archive (streamed to STDOUT by default)", true)
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
outfile := cmd.String([]string{"o", "-output"}, "", "Write to an file, instead of STDOUT")
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var (
output = cli.out
output io.Writer = cli.out
err error
)
if *outfile != "" {
-2
View File
@@ -8,8 +8,6 @@ import (
nwclient "github.com/docker/libnetwork/client"
)
// CmdService is used to manage network services.
// service command is user to publish, attach and list a service from a container.
func (cli *DockerCli) CmdService(args ...string) error {
nCli := nwclient.NewNetworkCli(cli.out, cli.err, nwclient.CallFunc(cli.callWrapper))
args = append([]string{"service"}, args...)
+8 -26
View File
@@ -25,8 +25,6 @@ type containerStats struct {
MemoryPercentage float64
NetworkRx float64
NetworkTx float64
BlockRead float64
BlockWrite float64
mu sync.RWMutex
err error
}
@@ -65,10 +63,9 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
cpuPercent = 0.0
)
previousCPU = v.PreCPUStats.CPUUsage.TotalUsage
previousSystem = v.PreCPUStats.SystemUsage
previousCPU = v.PreCpuStats.CpuUsage.TotalUsage
previousSystem = v.PreCpuStats.SystemUsage
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
blkRead, blkWrite := calculateBlockIO(v.BlkioStats)
s.mu.Lock()
s.CPUPercentage = cpuPercent
s.Memory = float64(v.MemoryStats.Usage)
@@ -76,8 +73,6 @@ func (s *containerStats) Collect(cli *DockerCli, streamStats bool) {
s.MemoryPercentage = memPercent
s.NetworkRx = float64(v.Network.RxBytes)
s.NetworkTx = float64(v.Network.TxBytes)
s.BlockRead = float64(blkRead)
s.BlockWrite = float64(blkWrite)
s.mu.Unlock()
u <- nil
if !streamStats {
@@ -115,13 +110,12 @@ func (s *containerStats) Display(w io.Writer) error {
if s.err != nil {
return s.err
}
fmt.Fprintf(w, "%s\t%.2f%%\t%s / %s\t%.2f%%\t%s / %s\t%s / %s\n",
fmt.Fprintf(w, "%s\t%.2f%%\t%s/%s\t%.2f%%\t%s/%s\n",
s.Name,
s.CPUPercentage,
units.HumanSize(s.Memory), units.HumanSize(s.MemoryLimit),
s.MemoryPercentage,
units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx),
units.HumanSize(s.BlockRead), units.HumanSize(s.BlockWrite))
units.HumanSize(s.NetworkRx), units.HumanSize(s.NetworkTx))
return nil
}
@@ -148,7 +142,7 @@ func (cli *DockerCli) CmdStats(args ...string) error {
fmt.Fprint(cli.out, "\033[2J")
fmt.Fprint(cli.out, "\033[H")
}
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE / LIMIT\tMEM %\tNET I/O\tBLOCK I/O\n")
io.WriteString(w, "CONTAINER\tCPU %\tMEM USAGE/LIMIT\tMEM %\tNET I/O\n")
}
for _, n := range names {
s := &containerStats{Name: n}
@@ -196,25 +190,13 @@ func calculateCPUPercent(previousCPU, previousSystem uint64, v *types.Stats) flo
var (
cpuPercent = 0.0
// calculate the change for the cpu usage of the container in between readings
cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage - previousCPU)
cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCPU)
// calculate the change for the entire system between readings
systemDelta = float64(v.CPUStats.SystemUsage - previousSystem)
systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
)
if systemDelta > 0.0 && cpuDelta > 0.0 {
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CpuStats.CpuUsage.PercpuUsage)) * 100.0
}
return cpuPercent
}
func calculateBlockIO(blkio types.BlkioStats) (blkRead uint64, blkWrite uint64) {
for _, bioEntry := range blkio.IoServiceBytesRecursive {
switch strings.ToLower(bioEntry.Op) {
case "read":
blkRead = blkRead + bioEntry.Value
case "write":
blkWrite = blkWrite + bioEntry.Value
}
}
return
}
+1 -18
View File
@@ -4,8 +4,6 @@ import (
"bytes"
"sync"
"testing"
"github.com/docker/docker/api/types"
)
func TestDisplay(t *testing.T) {
@@ -17,8 +15,6 @@ func TestDisplay(t *testing.T) {
MemoryPercentage: 100.0 / 2048.0 * 100.0,
NetworkRx: 100 * 1024 * 1024,
NetworkTx: 800 * 1024 * 1024,
BlockRead: 100 * 1024 * 1024,
BlockWrite: 800 * 1024 * 1024,
mu: sync.RWMutex{},
}
var b bytes.Buffer
@@ -26,21 +22,8 @@ func TestDisplay(t *testing.T) {
t.Fatalf("c.Display() gave error: %s", err)
}
got := b.String()
want := "app\t30.00%\t104.9 MB / 2.147 GB\t4.88%\t104.9 MB / 838.9 MB\t104.9 MB / 838.9 MB\n"
want := "app\t30.00%\t104.9 MB/2.147 GB\t4.88%\t104.9 MB/838.9 MB\n"
if got != want {
t.Fatalf("c.Display() = %q, want %q", got, want)
}
}
func TestCalculBlockIO(t *testing.T) {
blkio := types.BlkioStats{
IoServiceBytesRecursive: []types.BlkioStatEntry{{8, 0, "read", 1234}, {8, 1, "read", 4567}, {8, 0, "write", 123}, {8, 1, "write", 456}},
}
blkRead, blkWrite := calculateBlockIO(blkio)
if blkRead != 5801 {
t.Fatalf("blkRead = %d, want 5801", blkRead)
}
if blkWrite != 579 {
t.Fatalf("blkWrite = %d, want 579", blkWrite)
}
}
+9 -28
View File
@@ -13,7 +13,6 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"time"
@@ -177,16 +176,11 @@ func convertTarget(t client.Target) (target, error) {
}
func (cli *DockerCli) getPassphraseRetriever() passphrase.Retriever {
aliasMap := map[string]string{
"root": "offline",
"snapshot": "tagging",
"targets": "tagging",
}
baseRetriever := passphrase.PromptRetrieverWithInOut(cli.in, cli.out, aliasMap)
baseRetriever := passphrase.PromptRetrieverWithInOut(cli.in, cli.out)
env := map[string]string{
"root": os.Getenv("DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE"),
"snapshot": os.Getenv("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE"),
"targets": os.Getenv("DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE"),
"root": os.Getenv("DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE"),
"targets": os.Getenv("DOCKER_CONTENT_TRUST_TARGET_PASSPHRASE"),
"snapshot": os.Getenv("DOCKER_CONTENT_TRUST_SNAPSHOT_PASSPHRASE"),
}
return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) {
if v := env[alias]; v != "" {
@@ -317,22 +311,6 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
return nil
}
func selectKey(keys map[string]string) string {
if len(keys) == 0 {
return ""
}
keyIDs := []string{}
for k := range keys {
keyIDs = append(keyIDs, k)
}
// TODO(dmcgowan): let user choose if multiple keys, now pick consistently
sort.Strings(keyIDs)
return keyIDs[0]
}
func targetStream(in io.Writer) (io.WriteCloser, <-chan []target) {
r, w := io.Pipe()
out := io.MultiWriter(in, w)
@@ -431,13 +409,16 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
ks := repo.KeyStoreManager
keys := ks.RootKeyStore().ListKeys()
var rootKey string
rootKey := selectKey(keys)
if rootKey == "" {
if len(keys) == 0 {
rootKey, err = ks.GenRootKey("ecdsa")
if err != nil {
return err
}
} else {
// TODO(dmcgowan): let user choose
rootKey = keys[0]
}
cryptoService, err := ks.GetRootCryptoService(rootKey)
+39 -43
View File
@@ -30,7 +30,7 @@ import (
)
var (
errConnectionFailed = errors.New("Cannot connect to the Docker daemon. Is the docker daemon running on this host?")
errConnectionRefused = errors.New("Cannot connect to the Docker daemon. Is 'docker -d' running on this host?")
)
type serverResponse struct {
@@ -94,14 +94,13 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
if resp != nil {
serverResp.statusCode = resp.StatusCode
}
if err != nil {
if types.IsTimeout(err) || strings.Contains(err.Error(), "connection refused") || strings.Contains(err.Error(), "dial unix") {
return serverResp, errConnectionFailed
if strings.Contains(err.Error(), "connection refused") {
return serverResp, errConnectionRefused
}
if cli.tlsConfig == nil && strings.Contains(err.Error(), "malformed HTTP response") {
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err)
if cli.tlsConfig == nil {
return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?\n* Is your docker daemon up and running?", err)
}
if cli.tlsConfig != nil && strings.Contains(err.Error(), "remote error: bad certificate") {
return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err)
@@ -126,51 +125,48 @@ func (cli *DockerCli) clientRequest(method, path string, in io.Reader, headers m
return serverResp, nil
}
// cmdAttempt builds the corresponding registry Auth Header from the given
// authConfig. It returns the servers body, status, error response
func (cli *DockerCli) cmdAttempt(authConfig cliconfig.AuthConfig, method, path string, in io.Reader, out io.Writer) (io.ReadCloser, int, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return nil, -1, err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
// begin the request
serverResp, err := cli.clientRequest(method, path, in, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
if err == nil && out != nil {
// If we are streaming output, complete the stream since
// errors may not appear until later.
err = cli.streamBody(serverResp.body, serverResp.header.Get("Content-Type"), true, out, nil)
}
if err != nil {
// Since errors in a stream appear after status 200 has been written,
// we may need to change the status code.
if strings.Contains(err.Error(), "Authentication is required") ||
strings.Contains(err.Error(), "Status 401") ||
strings.Contains(err.Error(), "401 Unauthorized") ||
strings.Contains(err.Error(), "status code 401") {
serverResp.statusCode = http.StatusUnauthorized
}
}
return serverResp.body, serverResp.statusCode, err
}
func (cli *DockerCli) clientRequestAttemptLogin(method, path string, in io.Reader, out io.Writer, index *registry.IndexInfo, cmdName string) (io.ReadCloser, int, error) {
cmdAttempt := func(authConfig cliconfig.AuthConfig) (io.ReadCloser, int, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return nil, -1, err
}
registryAuthHeader := []string{
base64.URLEncoding.EncodeToString(buf),
}
// begin the request
serverResp, err := cli.clientRequest(method, path, in, map[string][]string{
"X-Registry-Auth": registryAuthHeader,
})
if err == nil && out != nil {
// If we are streaming output, complete the stream since
// errors may not appear until later.
err = cli.streamBody(serverResp.body, serverResp.header.Get("Content-Type"), true, out, nil)
}
if err != nil {
// Since errors in a stream appear after status 200 has been written,
// we may need to change the status code.
if strings.Contains(err.Error(), "Authentication is required") ||
strings.Contains(err.Error(), "Status 401") ||
strings.Contains(err.Error(), "401 Unauthorized") ||
strings.Contains(err.Error(), "status code 401") {
serverResp.statusCode = http.StatusUnauthorized
}
}
return serverResp.body, serverResp.statusCode, err
}
// Resolve the Auth config relevant for this server
authConfig := registry.ResolveAuthConfig(cli.configFile, index)
body, statusCode, err := cli.cmdAttempt(authConfig, method, path, in, out)
body, statusCode, err := cmdAttempt(authConfig)
if statusCode == http.StatusUnauthorized {
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
if err = cli.CmdLogin(index.GetAuthConfigKey()); err != nil {
return nil, -1, err
}
authConfig = registry.ResolveAuthConfig(cli.configFile, index)
return cli.cmdAttempt(authConfig, method, path, in, out)
return cmdAttempt(authConfig)
}
return body, statusCode, err
}
@@ -281,7 +277,7 @@ func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
serverResp, err := cli.call("GET", "/containers/"+containerID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != errConnectionFailed {
if err != errConnectionRefused {
return false, -1, err
}
return false, -1, nil
@@ -303,7 +299,7 @@ func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
serverResp, err := cli.call("GET", "/exec/"+execID+"/json", nil, nil)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != errConnectionFailed {
if err != errConnectionRefused {
return false, -1, err
}
return false, -1, nil
+7 -7
View File
@@ -13,9 +13,9 @@ import (
"github.com/docker/docker/utils"
)
var versionTemplate = `Client:
var VersionTemplate = `Client:
Version: {{.Client.Version}}
API version: {{.Client.APIVersion}}
API version: {{.Client.ApiVersion}}
Go version: {{.Client.GoVersion}}
Git commit: {{.Client.GitCommit}}
Built: {{.Client.BuildTime}}
@@ -24,14 +24,14 @@ var versionTemplate = `Client:
Server:
Version: {{.Server.Version}}
API version: {{.Server.APIVersion}}
API version: {{.Server.ApiVersion}}
Go version: {{.Server.GoVersion}}
Git commit: {{.Server.GitCommit}}
Built: {{.Server.BuildTime}}
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}}
Experimental: {{.Server.Experimental}}{{end}}{{end}}`
type versionData struct {
type VersionData struct {
Client types.Version
ServerOK bool
Server types.Version
@@ -49,7 +49,7 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
cmd.ParseFlags(args, true)
if *tmplStr == "" {
*tmplStr = versionTemplate
*tmplStr = VersionTemplate
}
var tmpl *template.Template
@@ -58,10 +58,10 @@ func (cli *DockerCli) CmdVersion(args ...string) (err error) {
Status: "Template parsing error: " + err.Error()}
}
vd := versionData{
vd := VersionData{
Client: types.Version{
Version: dockerversion.VERSION,
APIVersion: api.Version,
ApiVersion: api.Version,
GoVersion: runtime.Version(),
GitCommit: dockerversion.GITCOMMIT,
BuildTime: dockerversion.BUILDTIME,
-232
View File
@@ -1,232 +0,0 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/url"
"text/tabwriter"
"text/template"
"github.com/docker/docker/api/types"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers/filters"
)
// CmdVolume is the parent subcommand for all volume commands
//
// Usage: docker volume <COMMAND> <OPTS>
func (cli *DockerCli) CmdVolume(args ...string) error {
description := "Manage Docker volumes\n\nCommands:\n"
commands := [][]string{
{"create", "Create a volume"},
{"inspect", "Return low-level information on a volume"},
{"ls", "List volumes"},
{"rm", "Remove a volume"},
}
for _, cmd := range commands {
description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
}
description += "\nRun 'docker volume COMMAND --help' for more information on a command."
cmd := Cli.Subcmd("volume", []string{"[COMMAND]"}, description, true)
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
return cli.CmdVolumeLs(args...)
}
// CmdVolumeLs outputs a list of Docker volumes.
//
// Usage: docker volume ls [OPTIONS]
func (cli *DockerCli) CmdVolumeLs(args ...string) error {
cmd := Cli.Subcmd("volume ls", nil, "List volumes", true)
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display volume names")
flFilter := opts.NewListOpts(nil)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
volFilterArgs := filters.Args{}
for _, f := range flFilter.GetAll() {
var err error
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
if err != nil {
return err
}
}
v := url.Values{}
if len(volFilterArgs) > 0 {
filterJSON, err := filters.ToParam(volFilterArgs)
if err != nil {
return err
}
v.Set("filters", filterJSON)
}
resp, err := cli.call("GET", "/volumes?"+v.Encode(), nil, nil)
if err != nil {
return err
}
var volumes types.VolumesListResponse
if err := json.NewDecoder(resp.body).Decode(&volumes); err != nil {
return err
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprintf(w, "DRIVER \tVOLUME NAME")
fmt.Fprintf(w, "\n")
}
for _, vol := range volumes.Volumes {
if *quiet {
fmt.Fprintln(w, vol.Name)
continue
}
fmt.Fprintf(w, "%s\t%s\n", vol.Driver, vol.Name)
}
w.Flush()
return nil
}
// CmdVolumeInspect displays low-level information on one or more volumes.
//
// Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
cmd := Cli.Subcmd("volume inspect", []string{"[VOLUME NAME]"}, "Return low-level information on a volume", true)
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template.")
if err := cmd.Parse(args); err != nil {
return nil
}
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var tmpl *template.Template
if *tmplStr != "" {
var err error
tmpl, err = template.New("").Funcs(funcMap).Parse(*tmplStr)
if err != nil {
return err
}
}
var status = 0
var volumes []*types.Volume
for _, name := range cmd.Args() {
resp, err := cli.call("GET", "/volumes/"+name, nil, nil)
if err != nil {
return err
}
var volume types.Volume
if err := json.NewDecoder(resp.body).Decode(&volume); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
if tmpl == nil {
volumes = append(volumes, &volume)
continue
}
if err := tmpl.Execute(cli.out, &volume); err != nil {
if err := tmpl.Execute(cli.out, &volume); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
}
io.WriteString(cli.out, "\n")
}
if tmpl != nil {
return nil
}
b, err := json.MarshalIndent(volumes, "", " ")
if err != nil {
return err
}
_, err = io.Copy(cli.out, bytes.NewReader(b))
if err != nil {
return err
}
io.WriteString(cli.out, "\n")
if status != 0 {
return Cli.StatusError{StatusCode: status}
}
return nil
}
// CmdVolumeCreate creates a new container from a given image.
//
// Usage: docker volume create [OPTIONS]
func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
cmd := Cli.Subcmd("volume create", nil, "Create a volume", true)
flDriver := cmd.String([]string{"d", "-driver"}, "local", "Specify volume driver name")
flName := cmd.String([]string{"-name"}, "", "Specify volume name")
flDriverOpts := opts.NewMapOpts(nil, nil)
cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
cmd.Require(flag.Exact, 0)
cmd.ParseFlags(args, true)
volReq := &types.VolumeCreateRequest{
Driver: *flDriver,
DriverOpts: flDriverOpts.GetAll(),
}
if *flName != "" {
volReq.Name = *flName
}
resp, err := cli.call("POST", "/volumes", volReq, nil)
if err != nil {
return err
}
var vol types.Volume
if err := json.NewDecoder(resp.body).Decode(&vol); err != nil {
return err
}
fmt.Fprintf(cli.out, "%s\n", vol.Name)
return nil
}
// CmdVolumeRm removes one or more containers.
//
// Usage: docker volume rm VOLUME [VOLUME...]
func (cli *DockerCli) CmdVolumeRm(args ...string) error {
cmd := Cli.Subcmd("volume rm", []string{"[NAME]"}, "Remove a volume", true)
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
var status = 0
for _, name := range cmd.Args() {
_, err := cli.call("DELETE", "/volumes/"+name, nil, nil)
if err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
status = 1
continue
}
fmt.Fprintf(cli.out, "%s\n", name)
}
if status != 0 {
return Cli.StatusError{StatusCode: status}
}
return nil
}
+12 -17
View File
@@ -16,26 +16,22 @@ import (
// Common constants for daemon and client.
const (
// Version of Current REST API
Version version.Version = "1.21"
// Current REST API version
Version version.Version = "1.20"
// MinVersion represents Minimun REST API version supported
// Minimun REST API version supported
MinVersion version.Version = "1.12"
// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
// Default filename with Docker commands, read by docker build
DefaultDockerfileName string = "Dockerfile"
)
// byPrivatePort is temporary type used to sort types.Port by PrivatePort
type byPrivatePort []types.Port
type ByPrivatePort []types.Port
func (r byPrivatePort) Len() int { return len(r) }
func (r byPrivatePort) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r byPrivatePort) Less(i, j int) bool { return r[i].PrivatePort < r[j].PrivatePort }
func (r ByPrivatePort) Len() int { return len(r) }
func (r ByPrivatePort) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r ByPrivatePort) Less(i, j int) bool { return r[i].PrivatePort < r[j].PrivatePort }
// DisplayablePorts returns formatted string representing open ports of container
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
// it's used by command 'docker ps'
func DisplayablePorts(ports []types.Port) string {
var (
result = []string{}
@@ -45,7 +41,7 @@ func DisplayablePorts(ports []types.Port) string {
)
firstInGroupMap = make(map[string]int)
lastInGroupMap = make(map[string]int)
sort.Sort(byPrivatePort(ports))
sort.Sort(ByPrivatePort(ports))
for _, port := range ports {
var (
current = port.PrivatePort
@@ -73,18 +69,18 @@ func DisplayablePorts(ports []types.Port) string {
lastInGroupMap[portKey] = current
continue
}
result = append(result, formGroup(portKey, firstInGroup, lastInGroup))
result = append(result, FormGroup(portKey, firstInGroup, lastInGroup))
firstInGroupMap[portKey] = current
lastInGroupMap[portKey] = current
}
for portKey, firstInGroup := range firstInGroupMap {
result = append(result, formGroup(portKey, firstInGroup, lastInGroupMap[portKey]))
result = append(result, FormGroup(portKey, firstInGroup, lastInGroupMap[portKey]))
}
result = append(result, hostMappings...)
return strings.Join(result, ", ")
}
func formGroup(key string, start, last int) string {
func FormGroup(key string, start, last int) string {
var (
group string
parts = strings.Split(key, "/")
@@ -106,7 +102,6 @@ func formGroup(key string, start, last int) string {
return fmt.Sprintf("%s/%s", group, groupType)
}
// MatchesContentType validates the content type against the expected one
func MatchesContentType(contentType, expectedType string) bool {
mimetype, _, err := mime.ParseMediaType(contentType)
if err != nil {
-282
View File
@@ -1,282 +0,0 @@
package api
import (
"io/ioutil"
"path/filepath"
"testing"
"github.com/docker/docker/api/types"
"os"
)
type ports struct {
ports []types.Port
expected string
}
// DisplayablePorts
func TestDisplayablePorts(t *testing.T) {
cases := []ports{
{
[]types.Port{
{
PrivatePort: 9988,
Type: "tcp",
},
},
"9988/tcp"},
{
[]types.Port{
{
PrivatePort: 9988,
Type: "udp",
},
},
"9988/udp",
},
{
[]types.Port{
{
IP: "0.0.0.0",
PrivatePort: 9988,
Type: "tcp",
},
},
"0.0.0.0:0->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
},
},
"9988/tcp",
},
{
[]types.Port{
{
IP: "4.3.2.1",
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
},
},
"4.3.2.1:8899->9988/tcp",
},
{
[]types.Port{
{
IP: "4.3.2.1",
PrivatePort: 9988,
PublicPort: 9988,
Type: "tcp",
},
},
"4.3.2.1:9988->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
Type: "udp",
}, {
PrivatePort: 9988,
Type: "udp",
},
},
"9988/udp, 9988/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PublicPort: 9998,
PrivatePort: 9998,
Type: "udp",
}, {
IP: "1.2.3.4",
PublicPort: 9999,
PrivatePort: 9999,
Type: "udp",
},
},
"1.2.3.4:9998-9999->9998-9999/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PublicPort: 8887,
PrivatePort: 9998,
Type: "udp",
}, {
IP: "1.2.3.4",
PublicPort: 8888,
PrivatePort: 9999,
Type: "udp",
},
},
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
},
{
[]types.Port{
{
PrivatePort: 9998,
Type: "udp",
}, {
PrivatePort: 9999,
Type: "udp",
},
},
"9998-9999/udp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PrivatePort: 6677,
PublicPort: 7766,
Type: "tcp",
}, {
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
},
},
"9988/udp, 1.2.3.4:7766->6677/tcp",
},
{
[]types.Port{
{
IP: "1.2.3.4",
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
}, {
IP: "1.2.3.4",
PrivatePort: 9988,
PublicPort: 8899,
Type: "tcp",
}, {
IP: "4.3.2.1",
PrivatePort: 2233,
PublicPort: 3322,
Type: "tcp",
},
},
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/udp, 1.2.3.4:8899->9988/tcp",
},
{
[]types.Port{
{
PrivatePort: 9988,
PublicPort: 8899,
Type: "udp",
}, {
IP: "1.2.3.4",
PrivatePort: 6677,
PublicPort: 7766,
Type: "tcp",
}, {
IP: "4.3.2.1",
PrivatePort: 2233,
PublicPort: 3322,
Type: "tcp",
},
},
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
},
}
for _, port := range cases {
actual := DisplayablePorts(port.ports)
if port.expected != actual {
t.Fatalf("Expected %s, got %s.", port.expected, actual)
}
}
}
// MatchesContentType
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()
}
}
// LoadOrCreateTrustKey
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpKeyFolderPath)
tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile")
if err != nil {
t.Fatal(err)
}
if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil {
t.Fatalf("expected an error, got nothing.")
}
}
func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) {
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpKeyFolderPath)
// Without the need to create the folder hierarchy
tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat(tmpKeyFile); err != nil {
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
}
// With the need to create the folder hierarchy as tmpKeyFie is in a path
// where some folder do not exists.
tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat(tmpKeyFile); err != nil {
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
}
// With no path at all
defer os.Remove("keyfile")
if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil {
t.Fatalf("expected a new key file, got : %v and %v", err, key)
}
if _, err := os.Stat("keyfile"); err != nil {
t.Fatalf("Expected to find a file keyfile, got %v", err)
}
}
func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) {
tmpKeyFile := filepath.Join("fixtures", "keyfile")
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
t.Fatalf("expected a key file, got : %v and %v", err, key)
}
}
-7
View File
@@ -1,7 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY
MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49
AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky
NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA==
-----END EC PRIVATE KEY-----
-26
View File
@@ -1,26 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/pkg/version"
)
func (s *Server) postAuth(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var config *cliconfig.AuthConfig
err := json.NewDecoder(r.Body).Decode(&config)
r.Body.Close()
if err != nil {
return err
}
status, err := s.daemon.RegistryService.Auth(config)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.AuthResponse{
Status: status,
})
}
-535
View File
@@ -1,535 +0,0 @@
package server
import (
"fmt"
"io"
"net/http"
"runtime"
"strconv"
"strings"
"time"
"golang.org/x/net/websocket"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func (s *Server) getContainersByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if version.LessThan("1.20") && runtime.GOOS != "windows" {
return getContainersByNameDownlevel(w, s, vars["name"])
}
containerJSON, err := s.daemon.ContainerInspect(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, containerJSON)
}
func (s *Server) getContainersJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
config := &daemon.ContainersConfig{
All: boolValue(r, "all"),
Size: boolValue(r, "size"),
Since: r.Form.Get("since"),
Before: r.Form.Get("before"),
Filters: r.Form.Get("filters"),
}
if tmpLimit := r.Form.Get("limit"); tmpLimit != "" {
limit, err := strconv.Atoi(tmpLimit)
if err != nil {
return err
}
config.Limit = limit
}
containers, err := s.daemon.Containers(config)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, containers)
}
func (s *Server) getContainersStats(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
stream := boolValueOrDefault(r, "stream", true)
var out io.Writer
if !stream {
w.Header().Set("Content-Type", "application/json")
out = w
} else {
out = ioutils.NewWriteFlusher(w)
}
var closeNotifier <-chan bool
if notifier, ok := w.(http.CloseNotifier); ok {
closeNotifier = notifier.CloseNotify()
}
config := &daemon.ContainerStatsConfig{
Stream: stream,
OutStream: out,
Stop: closeNotifier,
}
return s.daemon.ContainerStats(vars["name"], config)
}
func (s *Server) getContainersLogs(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// Validate args here, because we can't return not StatusOK after job.Run() call
stdout, stderr := boolValue(r, "stdout"), boolValue(r, "stderr")
if !(stdout || stderr) {
return fmt.Errorf("Bad parameters: you must choose at least one stream")
}
var since time.Time
if r.Form.Get("since") != "" {
s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
if err != nil {
return err
}
since = time.Unix(s, 0)
}
var closeNotifier <-chan bool
if notifier, ok := w.(http.CloseNotifier); ok {
closeNotifier = notifier.CloseNotify()
}
c, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
outStream := ioutils.NewWriteFlusher(w)
// write an empty chunk of data (this is to ensure that the
// HTTP Response is sent immediately, even if the container has
// not yet produced any data)
outStream.Write(nil)
logsConfig := &daemon.ContainerLogsConfig{
Follow: boolValue(r, "follow"),
Timestamps: boolValue(r, "timestamps"),
Since: since,
Tail: r.Form.Get("tail"),
UseStdout: stdout,
UseStderr: stderr,
OutStream: outStream,
Stop: closeNotifier,
}
if err := s.daemon.ContainerLogs(c, logsConfig); err != nil {
fmt.Fprintf(w, "Error running logs job: %s\n", err)
}
return nil
}
func (s *Server) getContainersExport(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
return s.daemon.ContainerExport(vars["name"], w)
}
func (s *Server) postContainersStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
// If contentLength is -1, we can assumed chunked encoding
// or more technically that the length is unknown
// https://golang.org/src/pkg/net/http/request.go#L139
// net/http otherwise seems to swallow any headers related to chunked encoding
// including r.TransferEncoding
// allow a nil body for backwards compatibility
var hostConfig *runconfig.HostConfig
if r.Body != nil && (r.ContentLength > 0 || r.ContentLength == -1) {
if err := checkForJSON(r); err != nil {
return err
}
c, err := runconfig.DecodeHostConfig(r.Body)
if err != nil {
return err
}
hostConfig = c
}
if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
if err.Error() == "Container already started" {
w.WriteHeader(http.StatusNotModified)
return nil
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersStop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
seconds, _ := strconv.Atoi(r.Form.Get("t"))
if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
if err.Error() == "Container already stopped" {
w.WriteHeader(http.StatusNotModified)
return nil
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersKill(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
var sig uint64
name := vars["name"]
// If we have a signal, look at it. Otherwise, do nothing
if sigStr := r.Form.Get("signal"); sigStr != "" {
// Check if we passed the signal as a number:
// The largest legal signal is 31, so let's parse on 5 bits
sigN, err := strconv.ParseUint(sigStr, 10, 5)
if err != nil {
// The signal is not a number, treat it as a string (either like
// "KILL" or like "SIGKILL")
syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
if !ok {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
sig = uint64(syscallSig)
} else {
sig = sigN
}
if sig == 0 {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
}
if err := s.daemon.ContainerKill(name, sig); err != nil {
_, isStopped := err.(daemon.ErrContainerNotRunning)
// Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20
// to keep backwards compatibility.
if version.GreaterThanOrEqualTo("1.20") || !isStopped {
return fmt.Errorf("Cannot kill container %s: %v", name, err)
}
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersRestart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
timeout, _ := strconv.Atoi(r.Form.Get("t"))
if err := s.daemon.ContainerRestart(vars["name"], timeout); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersPause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.ContainerPause(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersUnpause(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.ContainerUnpause(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersWait(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
status, err := s.daemon.ContainerWait(vars["name"], -1*time.Second)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.ContainerWaitResponse{
StatusCode: status,
})
}
func (s *Server) getContainersChanges(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
changes, err := s.daemon.ContainerChanges(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, changes)
}
func (s *Server) getContainersTop(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
procList, err := s.daemon.ContainerTop(vars["name"], r.Form.Get("ps_args"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, procList)
}
func (s *Server) postContainerRename(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
newName := r.Form.Get("name")
if err := s.daemon.ContainerRename(name, newName); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
var (
warnings []string
name = r.Form.Get("name")
)
config, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
if err != nil {
return err
}
adjustCPUShares := version.LessThan("1.19")
container, warnings, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerCreateResponse{
ID: container.ID,
Warnings: warnings,
})
}
func (s *Server) deleteContainers(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
config := &daemon.ContainerRmConfig{
ForceRemove: boolValue(r, "force"),
RemoveVolume: boolValue(r, "v"),
RemoveLink: boolValue(r, "link"),
}
if err := s.daemon.ContainerRm(name, config); err != nil {
// Force a 404 for the empty string
if strings.Contains(strings.ToLower(err.Error()), "prefix can't be empty") {
return fmt.Errorf("no such id: \"\"")
}
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
func (s *Server) postContainersResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
}
width, err := strconv.Atoi(r.Form.Get("w"))
if err != nil {
return err
}
return s.daemon.ContainerResize(vars["name"], height, width)
}
func (s *Server) postContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
inStream, outStream, err := hijackServer(w)
if err != nil {
return err
}
defer closeStreams(inStream, outStream)
if _, ok := r.Header["Upgrade"]; ok {
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
} else {
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
}
attachWithLogsConfig := &daemon.ContainerAttachWithLogsConfig{
InStream: inStream,
OutStream: outStream,
UseStdin: boolValue(r, "stdin"),
UseStdout: boolValue(r, "stdout"),
UseStderr: boolValue(r, "stderr"),
Logs: boolValue(r, "logs"),
Stream: boolValue(r, "stream"),
}
if err := s.daemon.ContainerAttachWithLogs(cont, attachWithLogsConfig); err != nil {
fmt.Fprintf(outStream, "Error attaching: %s\n", err)
}
return nil
}
func (s *Server) wsContainersAttach(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
cont, err := s.daemon.Get(vars["name"])
if err != nil {
return err
}
h := websocket.Handler(func(ws *websocket.Conn) {
defer ws.Close()
wsAttachWithLogsConfig := &daemon.ContainerWsAttachWithLogsConfig{
InStream: ws,
OutStream: ws,
ErrStream: ws,
Logs: boolValue(r, "logs"),
Stream: boolValue(r, "stream"),
}
if err := s.daemon.ContainerWsAttachWithLogs(cont, wsAttachWithLogsConfig); err != nil {
logrus.Errorf("Error attaching websocket: %s", err)
}
})
ws := websocket.Server{Handler: h, Handshake: nil}
ws.ServeHTTP(w, r)
return nil
}
-115
View File
@@ -1,115 +0,0 @@
package server
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/version"
)
// postContainersCopy is deprecated in favor of getContainersArchive.
func (s *Server) postContainersCopy(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := checkForJSON(r); err != nil {
return err
}
cfg := types.CopyConfig{}
if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
return err
}
if cfg.Resource == "" {
return fmt.Errorf("Path cannot be empty")
}
data, err := s.daemon.ContainerCopy(vars["name"], cfg.Resource)
if err != nil {
if strings.Contains(strings.ToLower(err.Error()), "no such id") {
w.WriteHeader(http.StatusNotFound)
return nil
}
if os.IsNotExist(err) {
return fmt.Errorf("Could not find the file %s in container %s", cfg.Resource, vars["name"])
}
return err
}
defer data.Close()
w.Header().Set("Content-Type", "application/x-tar")
if _, err := io.Copy(w, data); err != nil {
return err
}
return nil
}
// // Encode the stat to JSON, base64 encode, and place in a header.
func setContainerPathStatHeader(stat *types.ContainerPathStat, header http.Header) error {
statJSON, err := json.Marshal(stat)
if err != nil {
return err
}
header.Set(
"X-Docker-Container-Path-Stat",
base64.StdEncoding.EncodeToString(statJSON),
)
return nil
}
func (s *Server) headContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
stat, err := s.daemon.ContainerStatPath(v.name, v.path)
if err != nil {
return err
}
return setContainerPathStatHeader(stat, w.Header())
}
func (s *Server) getContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
tarArchive, stat, err := s.daemon.ContainerArchivePath(v.name, v.path)
if err != nil {
return err
}
defer tarArchive.Close()
if err := setContainerPathStatHeader(stat, w.Header()); err != nil {
return err
}
w.Header().Set("Content-Type", "application/x-tar")
_, err = io.Copy(w, tarArchive)
return err
}
func (s *Server) putContainersArchive(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v, err := archiveFormValues(r, vars)
if err != nil {
return err
}
noOverwriteDirNonDir := boolValue(r, "noOverwriteDirNonDir")
return s.daemon.ContainerExtractToDir(v.name, v.path, noOverwriteDirNonDir, r.Body)
}
-174
View File
@@ -1,174 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"runtime"
"strconv"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/parsers/filters"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/utils"
)
func (s *Server) getVersion(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
v := &types.Version{
Version: dockerversion.VERSION,
APIVersion: api.Version,
GitCommit: dockerversion.GITCOMMIT,
GoVersion: runtime.Version(),
Os: runtime.GOOS,
Arch: runtime.GOARCH,
BuildTime: dockerversion.BUILDTIME,
}
if version.GreaterThanOrEqualTo("1.19") {
v.Experimental = utils.ExperimentalBuild()
}
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
v.KernelVersion = kernelVersion.String()
}
return writeJSON(w, http.StatusOK, v)
}
func (s *Server) getInfo(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
info, err := s.daemon.SystemInfo()
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, info)
}
func (s *Server) getEvents(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var since int64 = -1
if r.Form.Get("since") != "" {
s, err := strconv.ParseInt(r.Form.Get("since"), 10, 64)
if err != nil {
return err
}
since = s
}
var until int64 = -1
if r.Form.Get("until") != "" {
u, err := strconv.ParseInt(r.Form.Get("until"), 10, 64)
if err != nil {
return err
}
until = u
}
timer := time.NewTimer(0)
timer.Stop()
if until > 0 {
dur := time.Unix(until, 0).Sub(time.Now())
timer = time.NewTimer(dur)
}
ef, err := filters.FromParam(r.Form.Get("filters"))
if err != nil {
return err
}
isFiltered := func(field string, filter []string) bool {
if len(field) == 0 {
return false
}
if len(filter) == 0 {
return false
}
for _, v := range filter {
if v == field {
return false
}
if strings.Contains(field, ":") {
image := strings.Split(field, ":")
if image[0] == v {
return false
}
}
}
return true
}
d := s.daemon
es := d.EventsService
w.Header().Set("Content-Type", "application/json")
outStream := ioutils.NewWriteFlusher(w)
outStream.Write(nil) // make sure response is sent immediately
enc := json.NewEncoder(outStream)
getContainerID := func(cn string) string {
c, err := d.Get(cn)
if err != nil {
return ""
}
return c.ID
}
sendEvent := func(ev *jsonmessage.JSONMessage) error {
//incoming container filter can be name,id or partial id, convert and replace as a full container id
for i, cn := range ef["container"] {
ef["container"][i] = getContainerID(cn)
}
if isFiltered(ev.Status, ef["event"]) || (isFiltered(ev.ID, ef["image"]) &&
isFiltered(ev.From, ef["image"])) || isFiltered(ev.ID, ef["container"]) {
return nil
}
return enc.Encode(ev)
}
current, l := es.Subscribe()
if since == -1 {
current = nil
}
defer es.Evict(l)
for _, ev := range current {
if ev.Time < since {
continue
}
if err := sendEvent(ev); err != nil {
return err
}
}
var closeNotify <-chan bool
if closeNotifier, ok := w.(http.CloseNotifier); ok {
closeNotify = closeNotifier.CloseNotify()
}
for {
select {
case ev := <-l:
jev, ok := ev.(*jsonmessage.JSONMessage)
if !ok {
continue
}
if err := sendEvent(jev); err != nil {
return err
}
case <-timer.C:
return nil
case <-closeNotify:
logrus.Debug("Client disconnected, stop sending events")
return nil
}
}
}
-127
View File
@@ -1,127 +0,0 @@
package server
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func (s *Server) getExecByID(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter 'id'")
}
eConfig, err := s.daemon.ContainerExecInspect(vars["id"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, eConfig)
}
func (s *Server) postContainerExecCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
name := vars["name"]
execConfig := &runconfig.ExecConfig{}
if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
return err
}
execConfig.Container = name
if len(execConfig.Cmd) == 0 {
return fmt.Errorf("No exec command specified")
}
// Register an instance of Exec in container.
id, err := s.daemon.ContainerExecCreate(execConfig)
if err != nil {
logrus.Errorf("Error setting up exec command in container %s: %s", name, err)
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
ID: id,
})
}
// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
func (s *Server) postContainerExecStart(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
execName = vars["name"]
stdin, inStream io.ReadCloser
stdout, stderr, outStream io.Writer
)
execStartCheck := &types.ExecStartCheck{}
if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
return err
}
if !execStartCheck.Detach {
var err error
// Setting up the streaming http interface.
inStream, outStream, err = hijackServer(w)
if err != nil {
return err
}
defer closeStreams(inStream, outStream)
if _, ok := r.Header["Upgrade"]; ok {
fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
} else {
fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
}
stdin = inStream
stdout = outStream
if !execStartCheck.Tty {
stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
}
} else {
outStream = w
}
// Now run the user process in container.
if err := s.daemon.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
fmt.Fprintf(outStream, "Error running exec in container: %v\n", err)
}
return nil
}
func (s *Server) postContainerExecResize(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
height, err := strconv.Atoi(r.Form.Get("h"))
if err != nil {
return err
}
width, err := strconv.Atoi(r.Form.Get("w"))
if err != nil {
return err
}
return s.daemon.ContainerExecResize(vars["name"], height, width)
}
+1 -2
View File
@@ -3,7 +3,6 @@ package server
import (
"fmt"
"net/http"
"path/filepath"
"strconv"
"strings"
)
@@ -44,7 +43,7 @@ func archiveFormValues(r *http.Request, vars map[string]string) (archiveOptions,
}
name := vars["name"]
path := filepath.FromSlash(r.Form.Get("path"))
path := r.Form.Get("path")
switch {
case name == "":
-425
View File
@@ -1,425 +0,0 @@
package server
import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/builder"
"github.com/docker/docker/cliconfig"
"github.com/docker/docker/graph"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
)
func (s *Server) postCommit(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
cname := r.Form.Get("container")
pause := boolValue(r, "pause")
if r.FormValue("pause") == "" && version.GreaterThanOrEqualTo("1.13") {
pause = true
}
c, _, err := runconfig.DecodeContainerConfig(r.Body)
if err != nil && err != io.EOF { //Do not fail if body is empty.
return err
}
commitCfg := &builder.CommitConfig{
Pause: pause,
Repo: r.Form.Get("repo"),
Tag: r.Form.Get("tag"),
Author: r.Form.Get("author"),
Comment: r.Form.Get("comment"),
Changes: r.Form["changes"],
Config: c,
}
imgID, err := builder.Commit(cname, s.daemon, commitCfg)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, &types.ContainerCommitResponse{
ID: imgID,
})
}
// Creates an image from Pull or from Import
func (s *Server) postImagesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
image = r.Form.Get("fromImage")
repo = r.Form.Get("repo")
tag = r.Form.Get("tag")
message = r.Form.Get("message")
)
authEncoded := r.Header.Get("X-Registry-Auth")
authConfig := &cliconfig.AuthConfig{}
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
authConfig = &cliconfig.AuthConfig{}
}
}
var (
err error
output = ioutils.NewWriteFlusher(w)
)
w.Header().Set("Content-Type", "application/json")
if image != "" { //pull
if tag == "" {
image, tag = parsers.ParseRepositoryTag(image)
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
imagePullConfig := &graph.ImagePullConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
OutStream: output,
}
err = s.daemon.Repositories().Pull(image, tag, imagePullConfig)
} else { //import
if tag == "" {
repo, tag = parsers.ParseRepositoryTag(repo)
}
src := r.Form.Get("fromSrc")
// 'err' MUST NOT be defined within this block, we need any error
// generated from the download to be available to the output
// stream processing below
var newConfig *runconfig.Config
newConfig, err = builder.BuildFromConfig(s.daemon, &runconfig.Config{}, r.Form["changes"])
if err != nil {
return err
}
err = s.daemon.Repositories().Import(src, repo, tag, message, r.Body, output, newConfig)
}
if err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) postImagesPush(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
metaHeaders := map[string][]string{}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
metaHeaders[k] = v
}
}
if err := parseForm(r); err != nil {
return err
}
authConfig := &cliconfig.AuthConfig{}
authEncoded := r.Header.Get("X-Registry-Auth")
if authEncoded != "" {
// the new format is to handle the authConfig as a header
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(authConfig); err != nil {
// to increase compatibility to existing api it is defaulting to be empty
authConfig = &cliconfig.AuthConfig{}
}
} else {
// the old format is supported for compatibility if there was no authConfig header
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return fmt.Errorf("Bad parameters and missing X-Registry-Auth: %v", err)
}
}
name := vars["name"]
output := ioutils.NewWriteFlusher(w)
imagePushConfig := &graph.ImagePushConfig{
MetaHeaders: metaHeaders,
AuthConfig: authConfig,
Tag: r.Form.Get("tag"),
OutStream: output,
}
w.Header().Set("Content-Type", "application/json")
if err := s.daemon.Repositories().Push(name, imagePushConfig); err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) getImagesGet(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
if err := parseForm(r); err != nil {
return err
}
w.Header().Set("Content-Type", "application/x-tar")
output := ioutils.NewWriteFlusher(w)
var names []string
if name, ok := vars["name"]; ok {
names = []string{name}
} else {
names = r.Form["names"]
}
if err := s.daemon.Repositories().ImageExport(names, output); err != nil {
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
output.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) postImagesLoad(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return s.daemon.Repositories().Load(r.Body, w)
}
func (s *Server) deleteImages(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
if name == "" {
return fmt.Errorf("image name cannot be blank")
}
force := boolValue(r, "force")
prune := !boolValue(r, "noprune")
list, err := s.daemon.ImageDelete(name, force, prune)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, list)
}
func (s *Server) getImagesByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
imageInspect, err := s.daemon.Repositories().Lookup(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, imageInspect)
}
func (s *Server) postBuild(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
var (
authConfigs = map[string]cliconfig.AuthConfig{}
authConfigsEncoded = r.Header.Get("X-Registry-Config")
buildConfig = builder.NewBuildConfig()
)
if authConfigsEncoded != "" {
authConfigsJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authConfigsEncoded))
if err := json.NewDecoder(authConfigsJSON).Decode(&authConfigs); err != nil {
// for a pull it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting
// to be empty.
}
}
w.Header().Set("Content-Type", "application/json")
if boolValue(r, "forcerm") && version.GreaterThanOrEqualTo("1.12") {
buildConfig.Remove = true
} else if r.FormValue("rm") == "" && version.GreaterThanOrEqualTo("1.12") {
buildConfig.Remove = true
} else {
buildConfig.Remove = boolValue(r, "rm")
}
if boolValue(r, "pull") && version.GreaterThanOrEqualTo("1.16") {
buildConfig.Pull = true
}
output := ioutils.NewWriteFlusher(w)
buildConfig.Stdout = output
buildConfig.Context = r.Body
buildConfig.RemoteURL = r.FormValue("remote")
buildConfig.DockerfileName = r.FormValue("dockerfile")
buildConfig.RepoName = r.FormValue("t")
buildConfig.SuppressOutput = boolValue(r, "q")
buildConfig.NoCache = boolValue(r, "nocache")
buildConfig.ForceRemove = boolValue(r, "forcerm")
buildConfig.AuthConfigs = authConfigs
buildConfig.MemorySwap = int64ValueOrZero(r, "memswap")
buildConfig.Memory = int64ValueOrZero(r, "memory")
buildConfig.CPUShares = int64ValueOrZero(r, "cpushares")
buildConfig.CPUPeriod = int64ValueOrZero(r, "cpuperiod")
buildConfig.CPUQuota = int64ValueOrZero(r, "cpuquota")
buildConfig.CPUSetCpus = r.FormValue("cpusetcpus")
buildConfig.CPUSetMems = r.FormValue("cpusetmems")
buildConfig.CgroupParent = r.FormValue("cgroupparent")
var buildUlimits = []*ulimit.Ulimit{}
ulimitsJSON := r.FormValue("ulimits")
if ulimitsJSON != "" {
if err := json.NewDecoder(strings.NewReader(ulimitsJSON)).Decode(&buildUlimits); err != nil {
return err
}
buildConfig.Ulimits = buildUlimits
}
// Job cancellation. Note: not all job types support this.
if closeNotifier, ok := w.(http.CloseNotifier); ok {
finished := make(chan struct{})
defer close(finished)
go func() {
select {
case <-finished:
case <-closeNotifier.CloseNotify():
logrus.Infof("Client disconnected, cancelling job: build")
buildConfig.Cancel()
}
}()
}
if err := builder.Build(s.daemon, buildConfig); err != nil {
// Do not write the error in the http output if it's still empty.
// This prevents from writing a 200(OK) when there is an interal error.
if !output.Flushed() {
return err
}
sf := streamformatter.NewJSONStreamFormatter()
w.Write(sf.FormatError(err))
}
return nil
}
func (s *Server) getImagesJSON(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
// FIXME: The filter parameter could just be a match filter
images, err := s.daemon.Repositories().Images(r.Form.Get("filters"), r.Form.Get("filter"), boolValue(r, "all"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, images)
}
func (s *Server) getImagesHistory(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if vars == nil {
return fmt.Errorf("Missing parameter")
}
name := vars["name"]
history, err := s.daemon.Repositories().History(name)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, history)
}
func (s *Server) postImagesTag(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if vars == nil {
return fmt.Errorf("Missing parameter")
}
repo := r.Form.Get("repo")
tag := r.Form.Get("tag")
force := boolValue(r, "force")
name := vars["name"]
if err := s.daemon.Repositories().Tag(repo, tag, name, force); err != nil {
return err
}
s.daemon.EventsService.Log("tag", utils.ImageReference(repo, tag), "")
w.WriteHeader(http.StatusCreated)
return nil
}
func (s *Server) getImagesSearch(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
var (
config *cliconfig.AuthConfig
authEncoded = r.Header.Get("X-Registry-Auth")
headers = map[string][]string{}
)
if authEncoded != "" {
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
// for a search it is not an error if no auth was given
// to increase compatibility with the existing api it is defaulting to be empty
config = &cliconfig.AuthConfig{}
}
}
for k, v := range r.Header {
if strings.HasPrefix(k, "X-Meta-") {
headers[k] = v
}
}
query, err := s.daemon.RegistryService.Search(r.Form.Get("term"), config, headers)
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, query.Results)
}
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/gorilla/mux"
)
func profilerSetup(mainRouter *mux.Router, path string) {
func ProfilerSetup(mainRouter *mux.Router, path string) {
var r = mainRouter.PathPrefix(path).Subrouter()
r.HandleFunc("/vars", expVars)
r.HandleFunc("/pprof/", pprof.Index)
+1347 -34
View File
File diff suppressed because it is too large Load Diff
@@ -1,9 +1,9 @@
// +build experimental,!windows
// +build experimental
package server
func (s *Server) registerSubRouter() {
httpHandler := s.daemon.NetworkAPIRouter()
httpHandler := s.daemon.NetworkApiRouter()
subrouter := s.router.PathPrefix("/v{version:[0-9.]+}/networks").Subrouter()
subrouter.Methods("GET", "POST", "PUT", "DELETE").HandlerFunc(httpHandler)
@@ -1,4 +1,4 @@
// +build freebsd linux
// +build linux
package server
@@ -8,12 +8,19 @@ import (
"net/http"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/sockets"
"github.com/docker/docker/pkg/systemd"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork/portallocator"
)
systemdActivation "github.com/coreos/go-systemd/activation"
systemdDaemon "github.com/coreos/go-systemd/daemon"
const (
// See http://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
linuxMinCpuShares = 2
linuxMaxCpuShares = 262144
)
// newServer sets up the required serverClosers and does protocol specific checking.
@@ -24,7 +31,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
)
switch proto {
case "fd":
ls, err = listenFD(addr)
ls, err = systemd.ListenFD(addr)
if err != nil {
return nil, err
}
@@ -33,7 +40,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
// won't be ready.
<-s.start
case "tcp":
l, err := s.initTCPSocket(addr)
l, err := s.initTcpSocket(addr)
if err != nil {
return nil, err
}
@@ -49,7 +56,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
}
var res []serverCloser
for _, l := range ls {
res = append(res, &HTTPServer{
res = append(res, &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
@@ -60,14 +67,11 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
return res, nil
}
// AcceptConnections allows clients to connect to the API server.
// Referenced Daemon is notified about this server, and waits for the
// daemon acknowledgement before the incoming connections are accepted.
func (s *Server) AcceptConnections(d *daemon.Daemon) {
// Tell the init daemon we are accepting requests
s.daemon = d
s.registerSubRouter()
go systemdDaemon.SdNotify("READY=1")
go systemd.SdNotify("READY=1")
// close the lock so the listeners start accepting connections
select {
case <-s.start:
@@ -103,43 +107,17 @@ func allocateDaemonPort(addr string) error {
return nil
}
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
// is only relevant on non-Windows daemons.
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
containerJSONRaw, err := s.daemon.ContainerInspectPre120(namevar)
if err != nil {
return err
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
if version.LessThan("1.19") {
if hostConfig.CpuShares > 0 {
// Handle unsupported CpuShares
if hostConfig.CpuShares < linuxMinCpuShares {
logrus.Warnf("Changing requested CpuShares of %d to minimum allowed of %d", hostConfig.CpuShares, linuxMinCpuShares)
hostConfig.CpuShares = linuxMinCpuShares
} else if hostConfig.CpuShares > linuxMaxCpuShares {
logrus.Warnf("Changing requested CpuShares of %d to maximum allowed of %d", hostConfig.CpuShares, linuxMaxCpuShares)
hostConfig.CpuShares = linuxMaxCpuShares
}
}
}
return writeJSON(w, http.StatusOK, containerJSONRaw)
}
// listenFD returns the specified socket activated files as a slice of
// net.Listeners or all of the activated files if "*" is given.
func listenFD(addr string) ([]net.Listener, error) {
// socket activation
listeners, err := systemdActivation.Listeners(false)
if err != nil {
return nil, err
}
if listeners == nil || len(listeners) == 0 {
return nil, fmt.Errorf("No sockets found")
}
// default to all fds just like unix:// and tcp://
if addr == "" {
addr = "*"
}
fdNum, _ := strconv.Atoi(addr)
fdOffset := fdNum - 3
if (addr != "*") && (len(listeners) < int(fdOffset)+1) {
return nil, fmt.Errorf("Too few socket activated files passed in")
}
if addr == "*" {
return listeners, nil
}
return []net.Listener{listeners[fdOffset]}, nil
}
+68
View File
@@ -0,0 +1,68 @@
// +build linux
package server
import (
"testing"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
func TestAdjustCpuSharesOldApi(t *testing.T) {
apiVersion := version.Version("1.18")
hostConfig := &runconfig.HostConfig{
CpuShares: linuxMinCpuShares - 1,
}
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMinCpuShares {
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares)
}
hostConfig.CpuShares = linuxMaxCpuShares + 1
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMaxCpuShares {
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares)
}
hostConfig.CpuShares = 0
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 0 {
t.Error("Expected CpuShares to be unchanged")
}
hostConfig.CpuShares = 1024
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 1024 {
t.Error("Expected CpuShares to be unchanged")
}
}
func TestAdjustCpuSharesNoAdjustment(t *testing.T) {
apiVersion := version.Version("1.19")
hostConfig := &runconfig.HostConfig{
CpuShares: linuxMinCpuShares - 1,
}
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMinCpuShares-1 {
t.Errorf("Expected CpuShares to be %d", linuxMinCpuShares-1)
}
hostConfig.CpuShares = linuxMaxCpuShares + 1
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != linuxMaxCpuShares+1 {
t.Errorf("Expected CpuShares to be %d", linuxMaxCpuShares+1)
}
hostConfig.CpuShares = 0
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 0 {
t.Error("Expected CpuShares to be unchanged")
}
hostConfig.CpuShares = 1024
adjustCpuShares(apiVersion, hostConfig)
if hostConfig.CpuShares != 1024 {
t.Error("Expected CpuShares to be unchanged")
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build !experimental windows
// +build !experimental
package server
+5 -7
View File
@@ -8,6 +8,8 @@ import (
"net/http"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/version"
"github.com/docker/docker/runconfig"
)
// NewServer sets up the required Server and does protocol specific checking.
@@ -17,7 +19,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
)
switch proto {
case "tcp":
l, err := s.initTCPSocket(addr)
l, err := s.initTcpSocket(addr)
if err != nil {
return nil, err
}
@@ -29,7 +31,7 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
var res []serverCloser
for _, l := range ls {
res = append(res, &HTTPServer{
res = append(res, &HttpServer{
&http.Server{
Addr: addr,
Handler: s.router,
@@ -41,7 +43,6 @@ func (s *Server) newServer(proto, addr string) ([]serverCloser, error) {
}
// AcceptConnections allows router to start listening for the incoming requests.
func (s *Server) AcceptConnections(d *daemon.Daemon) {
s.daemon = d
s.registerSubRouter()
@@ -57,8 +58,5 @@ func allocateDaemonPort(addr string) error {
return nil
}
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
// is only relevant on non-Windows daemons.
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
return nil
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
}
-65
View File
@@ -1,65 +0,0 @@
package server
import (
"encoding/json"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/version"
)
func (s *Server) getVolumesList(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
volumes, err := s.daemon.Volumes(r.Form.Get("filters"))
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, &types.VolumesListResponse{Volumes: volumes})
}
func (s *Server) getVolumeByName(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
v, err := s.daemon.VolumeInspect(vars["name"])
if err != nil {
return err
}
return writeJSON(w, http.StatusOK, v)
}
func (s *Server) postVolumesCreate(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := checkForJSON(r); err != nil {
return err
}
var req types.VolumeCreateRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return err
}
volume, err := s.daemon.VolumeCreate(req.Name, req.Driver, req.DriverOpts)
if err != nil {
return err
}
return writeJSON(w, http.StatusCreated, volume)
}
func (s *Server) deleteVolumes(version version.Version, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := parseForm(r); err != nil {
return err
}
if err := s.daemon.VolumeRm(vars["name"]); err != nil {
return err
}
w.WriteHeader(http.StatusNoContent)
return nil
}
-21
View File
@@ -1,21 +0,0 @@
package types
import (
"net"
"net/url"
)
// IsTimeout takes an error returned from (generally) the http package and determines if it is a timeout error.
func IsTimeout(err error) bool {
switch e := err.(type) {
case net.Error:
return e.Timeout()
case *url.Error:
if t, ok := e.Err.(net.Error); ok {
return t.Timeout()
}
return false
default:
return false
}
}
+12 -19
View File
@@ -1,10 +1,9 @@
// Package types is used for API stability in the types and response to the
// This package is used for API stability in the types and response to the
// consumers of the API stats endpoint.
package types
import "time"
// ThrottlingData stores CPU throttling stats of one running container
type ThrottlingData struct {
// Number of periods with throttling active
Periods uint64 `json:"periods"`
@@ -14,8 +13,8 @@ type ThrottlingData struct {
ThrottledTime uint64 `json:"throttled_time"`
}
// CPUUsage stores All CPU stats aggregated since container inception.
type CPUUsage struct {
// All CPU stats are aggregated since container inception.
type CpuUsage struct {
// Total CPU time consumed.
// Units: nanoseconds.
TotalUsage uint64 `json:"total_usage"`
@@ -30,14 +29,12 @@ type CPUUsage struct {
UsageInUsermode uint64 `json:"usage_in_usermode"`
}
// CPUStats aggregates and wraps all CPU related info of container
type CPUStats struct {
CPUUsage CPUUsage `json:"cpu_usage"`
type CpuStats struct {
CpuUsage CpuUsage `json:"cpu_usage"`
SystemUsage uint64 `json:"system_cpu_usage"`
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
}
// MemoryStats aggregates All memory stats since container inception
type MemoryStats struct {
// current res_counter usage for memory
Usage uint64 `json:"usage"`
@@ -51,7 +48,6 @@ type MemoryStats struct {
Limit uint64 `json:"limit"`
}
// BlkioStatEntry is one small entity to store a piece of Blkio stats
// TODO Windows: This can be factored out
type BlkioStatEntry struct {
Major uint64 `json:"major"`
@@ -60,7 +56,6 @@ type BlkioStatEntry struct {
Value uint64 `json:"value"`
}
// BlkioStats stores All IO service stats for data read and write
// TODO Windows: This can be factored out
type BlkioStats struct {
// number of bytes tranferred to and from the block device
@@ -74,9 +69,8 @@ type BlkioStats struct {
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive"`
}
// NetworkStats aggregates All network stats of one container
// TODO Windows: This will require refactoring
type NetworkStats struct {
type Network struct {
RxBytes uint64 `json:"rx_bytes"`
RxPackets uint64 `json:"rx_packets"`
RxErrors uint64 `json:"rx_errors"`
@@ -87,12 +81,11 @@ type NetworkStats struct {
TxDropped uint64 `json:"tx_dropped"`
}
// Stats is Ultimate struct aggregating all types of stats of one container
type Stats struct {
Read time.Time `json:"read"`
Network NetworkStats `json:"network,omitempty"`
PreCPUStats CPUStats `json:"precpu_stats,omitempty"`
CPUStats CPUStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
Read time.Time `json:"read"`
Network Network `json:"network,omitempty"`
PreCpuStats CpuStats `json:"precpu_stats,omitempty"`
CpuStats CpuStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
}
+35 -81
View File
@@ -19,41 +19,35 @@ type ContainerCreateResponse struct {
Warnings []string `json:"Warnings"`
}
// ContainerExecCreateResponse contains response of Remote API:
// POST "/containers/{name:.*}/exec"
// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
// ID is the exec ID.
ID string `json:"Id"`
}
// AuthResponse contains response of Remote API:
// POST "/auth"
// POST /auth
type AuthResponse struct {
// Status is the authentication status
Status string `json:"Status"`
}
// ContainerWaitResponse contains response of Remote API:
// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
// StatusCode is the status code of the wait job
StatusCode int `json:"StatusCode"`
}
// ContainerCommitResponse contains response of Remote API:
// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
ID string `json:"Id"`
}
// ContainerChange contains response of Remote API:
// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
Kind int
Path string
}
// ImageHistory contains response of Remote API:
// GET "/images/{name:.*}/history"
type ImageHistory struct {
ID string `json:"Id"`
@@ -64,40 +58,35 @@ type ImageHistory struct {
Comment string
}
// ImageDelete contains response of Remote API:
// DELETE "/images/{name:.*}"
type ImageDelete struct {
Untagged string `json:",omitempty"`
Deleted string `json:",omitempty"`
}
// Image contains response of Remote API:
// GET "/images/json"
type Image struct {
ID string `json:"Id"`
ParentID string `json:"ParentId"`
ParentId string
RepoTags []string
RepoDigests []string
Created int64
Size int64
VirtualSize int64
Created int
Size int
VirtualSize int
Labels map[string]string
}
// GraphDriverData returns Image's graph driver config info
// when calling inspect command
type GraphDriverData struct {
Name string
Data map[string]string
}
// ImageInspect contains response of Remote API:
// GET "/images/{name:.*}/json"
type ImageInspect struct {
ID string `json:"Id"`
Id string
Parent string
Comment string
Created string
Created time.Time
Container string
ContainerConfig *runconfig.Config
DockerVersion string
@@ -110,8 +99,7 @@ type ImageInspect struct {
GraphDriver GraphDriverData
}
// Port stores open ports info of container
// e.g. {"PrivatePort": 8080, "PublicPort": 80, "Type": "tcp"}
// GET "/containers/json"
type Port struct {
IP string `json:",omitempty"`
PrivatePort int
@@ -119,17 +107,15 @@ type Port struct {
Type string
}
// Container contains response of Remote API:
// GET "/containers/json"
type Container struct {
ID string `json:"Id"`
Names []string
Image string
Command string
Created int64
Created int
Ports []Port
SizeRw int64 `json:",omitempty"`
SizeRootFs int64 `json:",omitempty"`
SizeRw int `json:",omitempty"`
SizeRootFs int `json:",omitempty"`
Labels map[string]string
Status string
HostConfig struct {
@@ -137,35 +123,32 @@ type Container struct {
}
}
// CopyConfig contains request body of Remote API:
// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
Resource string
}
// ContainerPathStat is used to encode the header from
// GET "/containers/{name:.*}/archive"
// "Name" is the file or directory name.
// GET /containers/{name:.*}/archive
// "name" is the file or directory name.
// "path" is the absolute path to the resource in the container.
type ContainerPathStat struct {
Name string `json:"name"`
Size int64 `json:"size"`
Mode os.FileMode `json:"mode"`
Mtime time.Time `json:"mtime"`
LinkTarget string `json:"linkTarget"`
Name string `json:"name"`
Path string `json:"path"`
Size int64 `json:"size"`
Mode os.FileMode `json:"mode"`
Mtime time.Time `json:"mtime"`
}
// ContainerProcessList contains response of Remote API:
// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
Processes [][]string
Titles []string
}
// Version contains response of Remote API:
// GET "/version"
type Version struct {
Version string
APIVersion version.Version `json:"ApiVersion"`
ApiVersion version.Version
GitCommit string
GoVersion string
Os string
@@ -175,7 +158,6 @@ type Version struct {
BuildTime string `json:",omitempty"`
}
// Info contains response of Remote API:
// GET "/info"
type Info struct {
ID string
@@ -185,11 +167,11 @@ type Info struct {
DriverStatus [][2]string
MemoryLimit bool
SwapLimit bool
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
CPUCfsQuota bool `json:"CpuCfsQuota"`
CpuCfsPeriod bool
CpuCfsQuota bool
IPv4Forwarding bool
BridgeNfIptables bool
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
BridgeNfIp6tables bool
Debug bool
NFd int
OomKillDisable bool
@@ -207,15 +189,15 @@ type Info struct {
NCPU int
MemTotal int64
DockerRootDir string
HTTPProxy string `json:"HttpProxy"`
HTTPSProxy string `json:"HttpsProxy"`
HttpProxy string
HttpsProxy string
NoProxy string
Name string
Labels []string
ExperimentalBuild bool
}
// ExecStartCheck is a temp struct used by execStart
// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
// ExecStart will first check if it's detached
@@ -224,10 +206,7 @@ type ExecStartCheck struct {
Tty bool
}
// ContainerState stores container's running state
// it's part of ContainerJSONBase and will return by "inspect" command
type ContainerState struct {
Status string
Running bool
Paused bool
Restarting bool
@@ -236,15 +215,14 @@ type ContainerState struct {
Pid int
ExitCode int
Error string
StartedAt string
FinishedAt string
StartedAt time.Time
FinishedAt time.Time
}
// ContainerJSONBase contains response of Remote API:
// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
ID string `json:"Id"`
Created string
Id string
Created time.Time
Path string
Args []string
State *ContainerState
@@ -266,15 +244,13 @@ type ContainerJSONBase struct {
GraphDriver GraphDriverData
}
// ContainerJSON is newly used struct along with MountPoint
type ContainerJSON struct {
*ContainerJSONBase
Mounts []MountPoint
Config *runconfig.Config
}
// ContainerJSONPre120 is a backcompatibility struct along with ContainerConfig.
// Note this is not used by the Windows daemon.
// backcompatibility struct along with ContainerConfig
type ContainerJSONPre120 struct {
*ContainerJSONBase
Volumes map[string]string
@@ -282,15 +258,14 @@ type ContainerJSONPre120 struct {
Config *ContainerConfig
}
// ContainerConfig is a backcompatibility struct used in ContainerJSONPre120
type ContainerConfig struct {
*runconfig.Config
// backward compatibility, they now live in HostConfig
Memory int64
MemorySwap int64
CPUShares int64 `json:"CpuShares"`
CPUSet string `json:"CpuSet"`
CpuShares int64
Cpuset string
}
// MountPoint represents a mount point configuration inside the container.
@@ -299,27 +274,6 @@ type MountPoint struct {
Source string
Destination string
Driver string `json:",omitempty"`
Mode string
Mode string // this is internally named `Relabel`
RW bool
}
// Volume represents the configuration of a volume for the remote API
type Volume struct {
Name string // Name is the name of the volume
Driver string // Driver is the Driver name used to create the volume
Mountpoint string // Mountpoint is the location on disk of the volume
}
// VolumesListResponse contains the response for the remote API:
// GET "/volumes"
type VolumesListResponse struct {
Volumes []*Volume // Volumes is the list of volumes being returned
}
// VolumeCreateRequest contains the response for the remote API:
// POST "/volumes"
type VolumeCreateRequest struct {
Name string // Name is the requested name of the volume
Driver string // Driver is the name of the driver that should be used to create the volume
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
}
+1 -13
View File
@@ -38,7 +38,6 @@ func NewBFlags() *BFlags {
}
// AddBool adds a bool flag to BFlags
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) AddBool(name string, def bool) *Flag {
flag := bf.addFlag(name, boolType)
if flag == nil {
@@ -53,7 +52,6 @@ func (bf *BFlags) AddBool(name string, def bool) *Flag {
}
// AddString adds a string flag to BFlags
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) AddString(name string, def string) *Flag {
flag := bf.addFlag(name, stringType)
if flag == nil {
@@ -63,9 +61,6 @@ func (bf *BFlags) AddString(name string, def string) *Flag {
return flag
}
// addFlag is a generic func used by the other AddXXX() func
// to add a new flag to the BFlags struct.
// Note, any error will be generated when Parse() is called (see Parse).
func (bf *BFlags) addFlag(name string, flagType FlagType) *Flag {
if _, ok := bf.flags[name]; ok {
bf.Err = fmt.Errorf("Duplicate flag defined: %s", name)
@@ -99,14 +94,7 @@ func (fl *Flag) IsTrue() bool {
return fl.Value == "true"
}
// Parse parses and checks if the BFlags is valid.
// Any error noticed during the AddXXX() funcs will be generated/returned
// here. We do this because an error during AddXXX() is more like a
// compile time error so it doesn't matter too much when we stop our
// processing as long as we do stop it, so this allows the code
// around AddXXX() to be just:
// defFlag := AddString("desription", "")
// w/o needing to add an if-statement around each one.
// Parse parses and checks if the BFlags is valid
func (bf *BFlags) Parse() error {
// If there was an error while defining the possible flags
// go ahead and bubble it back up here since we didn't do it
+36 -18
View File
@@ -10,7 +10,7 @@ package builder
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -20,8 +20,6 @@ import (
"github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig"
)
@@ -196,11 +194,7 @@ func from(b *builder, args []string, attributes map[string]bool, original string
name := args[0]
// Windows cannot support a container with no base image.
if name == NoBaseImageSpecifier {
if runtime.GOOS == "windows" {
return fmt.Errorf("Windows does not support FROM scratch")
}
b.image = ""
b.noBaseImage = true
return nil
@@ -273,15 +267,39 @@ func workdir(b *builder, args []string, attributes map[string]bool, original str
return err
}
// This is from the Dockerfile and will not necessarily be in platform
// specific semantics, hence ensure it is converted.
workdir := filepath.FromSlash(args[0])
// Note that workdir passed comes from the Dockerfile. Hence it is in
// Linux format using forward-slashes, even on Windows. However,
// b.Config.WorkingDir is in platform-specific notation (in other words
// on Windows will use `\`
workdir := args[0]
if !system.IsAbs(workdir) {
current := filepath.FromSlash(b.Config.WorkingDir)
workdir = filepath.Join(string(os.PathSeparator), current, workdir)
isAbs := false
if runtime.GOOS == "windows" {
// Alternate processing for Windows here is necessary as we can't call
// filepath.IsAbs(workDir) as that would verify Windows style paths,
// along with drive-letters (eg c:\pathto\file.txt). We (arguably
// correctly or not) check for both forward and back slashes as this
// is what the 1.4.2 GoLang implementation of IsAbs() does in the
// isSlash() function.
isAbs = workdir[0] == '\\' || workdir[0] == '/'
} else {
isAbs = filepath.IsAbs(workdir)
}
if !isAbs {
current := b.Config.WorkingDir
if runtime.GOOS == "windows" {
// Convert to Linux format before join
current = strings.Replace(current, "\\", "/", -1)
}
// Must use path.Join so works correctly on Windows, not filepath
workdir = path.Join("/", current, workdir)
}
// Convert to platform specific format
if runtime.GOOS == "windows" {
workdir = strings.Replace(workdir, "/", "\\", -1)
}
b.Config.WorkingDir = workdir
return b.commit("", b.Config.Cmd, fmt.Sprintf("WORKDIR %v", workdir))
@@ -330,7 +348,7 @@ func run(b *builder, args []string, attributes map[string]bool, original string)
b.Config.Cmd = config.Cmd
runconfig.Merge(b.Config, config)
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
logrus.Debugf("[BUILDER] Command to be executed: %v", b.Config.Cmd)
@@ -383,7 +401,7 @@ func cmd(b *builder, args []string, attributes map[string]bool, original string)
}
}
b.Config.Cmd = stringutils.NewStrSlice(cmdSlice...)
b.Config.Cmd = runconfig.NewCommand(cmdSlice...)
if err := b.commit("", b.Config.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
return err
@@ -414,16 +432,16 @@ func entrypoint(b *builder, args []string, attributes map[string]bool, original
switch {
case attributes["json"]:
// ENTRYPOINT ["echo", "hi"]
b.Config.Entrypoint = stringutils.NewStrSlice(parsed...)
b.Config.Entrypoint = runconfig.NewEntrypoint(parsed...)
case len(parsed) == 0:
// ENTRYPOINT []
b.Config.Entrypoint = nil
default:
// ENTRYPOINT echo hi
if runtime.GOOS != "windows" {
b.Config.Entrypoint = stringutils.NewStrSlice("/bin/sh", "-c", parsed[0])
b.Config.Entrypoint = runconfig.NewEntrypoint("/bin/sh", "-c", parsed[0])
} else {
b.Config.Entrypoint = stringutils.NewStrSlice("cmd", "/S /C", parsed[0])
b.Config.Entrypoint = runconfig.NewEntrypoint("cmd", "/S /C", parsed[0])
}
}
+1 -22
View File
@@ -24,7 +24,6 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/Sirupsen/logrus"
@@ -282,18 +281,11 @@ func (b *builder) readDockerfile() error {
// features.
func (b *builder) dispatch(stepN int, ast *parser.Node) error {
cmd := ast.Value
// To ensure the user is give a decent error message if the platform
// on which the daemon is running does not support a builder command.
if err := platformSupports(strings.ToLower(cmd)); err != nil {
return err
}
attrs := ast.Attributes
original := ast.Original
flags := ast.Flags
strs := []string{}
msg := fmt.Sprintf("Step %d : %s", stepN+1, strings.ToUpper(cmd))
msg := fmt.Sprintf("Step %d : %s", stepN, strings.ToUpper(cmd))
if len(ast.Flags) > 0 {
msg += " " + strings.Join(ast.Flags, " ")
@@ -357,16 +349,3 @@ func (b *builder) dispatch(stepN int, ast *parser.Node) error {
return fmt.Errorf("Unknown instruction: %s", strings.ToUpper(cmd))
}
// platformSupports is a short-term function to give users a quality error
// message if a Dockerfile uses a command not supported on the platform.
func platformSupports(command string) error {
if runtime.GOOS != "windows" {
return nil
}
switch command {
case "expose", "volume", "user":
return fmt.Errorf("The daemon on this platform does not support the command '%s'", command)
}
return nil
}
+30 -28
View File
@@ -33,7 +33,6 @@ import (
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/progressreader"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/tarsum"
"github.com/docker/docker/pkg/urlutil"
@@ -74,7 +73,7 @@ func (b *builder) readContext(context io.Reader) (err error) {
return
}
func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment string) error {
func (b *builder) commit(id string, autoCmd *runconfig.Command, comment string) error {
if b.disableCommit {
return nil
}
@@ -85,11 +84,11 @@ func (b *builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
if id == "" {
cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", "#(nop) "+comment)
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", "#(nop) "+comment)
} else {
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", "REM (nop) "+comment)
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", "REM (nop) "+comment)
}
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
hit, err := b.probeCache()
if err != nil {
@@ -216,11 +215,11 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
cmd := b.Config.Cmd
if runtime.GOOS != "windows" {
b.Config.Cmd = stringutils.NewStrSlice("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = runconfig.NewCommand("/bin/sh", "-c", fmt.Sprintf("#(nop) %s %s in %s", cmdName, srcHash, dest))
} else {
b.Config.Cmd = stringutils.NewStrSlice("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
b.Config.Cmd = runconfig.NewCommand("cmd", "/S /C", fmt.Sprintf("REM (nop) %s %s in %s", cmdName, srcHash, dest))
}
defer func(cmd *stringutils.StrSlice) { b.Config.Cmd = cmd }(cmd)
defer func(cmd *runconfig.Command) { b.Config.Cmd = cmd }(cmd)
hit, err := b.probeCache()
if err != nil {
@@ -231,7 +230,7 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
return nil
}
container, _, err := b.Daemon.ContainerCreate("", b.Config, nil, true)
container, _, err := b.Daemon.Create(b.Config, nil, "")
if err != nil {
return err
}
@@ -242,12 +241,20 @@ func (b *builder) runContextCommand(args []string, allowRemote bool, allowDecomp
}
defer container.Unmount()
if err := container.PrepareStorage(); err != nil {
return err
}
for _, ci := range copyInfos {
if err := b.addContext(container, ci.origPath, ci.destPath, ci.decompress); err != nil {
return err
}
}
if err := container.CleanupStorage(); err != nil {
return err
}
if err := b.commit(container.ID, cmd, fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)); err != nil {
return err
}
@@ -270,7 +277,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
// Twiddle the destPath when its a relative path - meaning, make it
// relative to the WORKINGDIR
if !system.IsAbs(destPath) {
if !filepath.IsAbs(destPath) {
hasSlash := strings.HasSuffix(destPath, string(os.PathSeparator))
destPath = filepath.Join(string(os.PathSeparator), filepath.FromSlash(b.Config.WorkingDir), destPath)
@@ -323,7 +330,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
In: resp.Body,
Out: b.OutOld,
Formatter: b.StreamFormatter,
Size: resp.ContentLength,
Size: int(resp.ContentLength),
NewLines: true,
ID: "",
Action: "Downloading",
@@ -348,11 +355,8 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
}
}
// Windows does not support UtimesNano.
if runtime.GOOS != "windows" {
if err := system.UtimesNano(tmpFileName, times); err != nil {
return err
}
if err := system.UtimesNano(tmpFileName, times); err != nil {
return err
}
ci.origPath = filepath.Join(filepath.Base(tmpDirName), filepath.Base(tmpFileName))
@@ -363,7 +367,7 @@ func calcCopyInfo(b *builder, cmdName string, cInfos *[]*copyInfo, origPath stri
if err != nil {
return err
}
path := filepath.FromSlash(u.Path) // Ensure in platform semantics
path := u.Path
if strings.HasSuffix(path, string(os.PathSeparator)) {
path = path[:len(path)-1]
}
@@ -535,11 +539,7 @@ func (b *builder) processImageFrom(img *image.Image) error {
// Process ONBUILD triggers if they exist
if nTriggers := len(b.Config.OnBuild); nTriggers != 0 {
word := "trigger"
if nTriggers > 1 {
word = "triggers"
}
fmt.Fprintf(b.ErrStream, "# Executing %d build %s...\n", nTriggers, word)
fmt.Fprintf(b.ErrStream, "# Executing %d build triggers\n", nTriggers)
}
// Copy the ONBUILD triggers, and remove them from the config, since the config will be committed.
@@ -547,7 +547,7 @@ func (b *builder) processImageFrom(img *image.Image) error {
b.Config.OnBuild = []string{}
// parse the ONBUILD triggers by invoking the parser
for _, step := range onBuildTriggers {
for stepN, step := range onBuildTriggers {
ast, err := parser.Parse(strings.NewReader(step))
if err != nil {
return err
@@ -561,6 +561,8 @@ func (b *builder) processImageFrom(img *image.Image) error {
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", n.Value)
}
fmt.Fprintf(b.OutStream, "Trigger %d, %s\n", stepN, step)
if err := b.dispatch(i, n); err != nil {
return err
}
@@ -605,9 +607,9 @@ func (b *builder) create() (*daemon.Container, error) {
b.Config.Image = b.image
hostConfig := &runconfig.HostConfig{
CPUShares: b.cpuShares,
CPUPeriod: b.cpuPeriod,
CPUQuota: b.cpuQuota,
CpuShares: b.cpuShares,
CpuPeriod: b.cpuPeriod,
CpuQuota: b.cpuQuota,
CpusetCpus: b.cpuSetCpus,
CpusetMems: b.cpuSetMems,
CgroupParent: b.cgroupParent,
@@ -619,7 +621,7 @@ func (b *builder) create() (*daemon.Container, error) {
config := *b.Config
// Create the container
c, warnings, err := b.Daemon.ContainerCreate("", b.Config, hostConfig, true)
c, warnings, err := b.Daemon.Create(b.Config, hostConfig, "")
if err != nil {
return nil, err
}
@@ -636,7 +638,7 @@ func (b *builder) create() (*daemon.Container, error) {
c.Path = s[0]
c.Args = s[1:]
} else {
config.Cmd = stringutils.NewStrSlice()
config.Cmd = runconfig.NewCommand()
}
return c, nil
@@ -1,4 +1,4 @@
// +build freebsd linux
// +build linux
package builder
+4 -10
View File
@@ -7,7 +7,6 @@ import (
"io"
"io/ioutil"
"os"
"runtime"
"strings"
"sync"
@@ -140,7 +139,7 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
}
defer f.Body.Close()
ct := f.Header.Get("Content-Type")
clen := f.ContentLength
clen := int(f.ContentLength)
contentType, bodyReader, err := inspectResponse(ct, f.Body, clen)
defer bodyReader.Close()
@@ -183,11 +182,11 @@ func Build(d *daemon.Daemon, buildConfig *Config) error {
builder := &builder{
Daemon: d,
OutStream: &streamformatter.StdoutFormatter{
OutStream: &streamformatter.StdoutFormater{
Writer: buildConfig.Stdout,
StreamFormatter: sf,
},
ErrStream: &streamformatter.StderrFormatter{
ErrStream: &streamformatter.StderrFormater{
Writer: buildConfig.Stdout,
StreamFormatter: sf,
},
@@ -280,11 +279,6 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
return "", err
}
// It is not possible to commit a running container on Windows
if runtime.GOOS == "windows" && container.IsRunning() {
return "", fmt.Errorf("Windows does not support commit of a running container")
}
if c.Config == nil {
c.Config = &runconfig.Config{}
}
@@ -322,7 +316,7 @@ func Commit(name string, d *daemon.Daemon, c *CommitConfig) (string, error) {
// - an io.Reader for the response body
// - an error value which will be non-nil either when something goes wrong while
// reading bytes from r or when the detected content-type is not acceptable.
func inspectResponse(ct string, r io.ReadCloser, clen int64) (string, io.ReadCloser, error) {
func inspectResponse(ct string, r io.ReadCloser, clen int) (string, io.ReadCloser, error) {
plen := clen
if plen <= 0 || plen > maxPreambleLength {
plen = maxPreambleLength
+4 -4
View File
@@ -31,7 +31,7 @@ func TestInspectEmptyResponse(t *testing.T) {
func TestInspectResponseBinary(t *testing.T) {
ct := "application/octet-stream"
br := ioutil.NopCloser(bytes.NewReader(binaryContext))
contentType, bReader, err := inspectResponse(ct, br, int64(len(binaryContext)))
contentType, bReader, err := inspectResponse(ct, br, len(binaryContext))
if err != nil {
t.Fatal(err)
}
@@ -56,7 +56,7 @@ func TestResponseUnsupportedContentType(t *testing.T) {
content := []byte(textPlainDockerfile)
ct := "application/json"
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bReader, err := inspectResponse(ct, br, int64(len(textPlainDockerfile)))
contentType, bReader, err := inspectResponse(ct, br, len(textPlainDockerfile))
if err == nil {
t.Fatal("Should have returned an error on content-type 'application/json'")
@@ -77,7 +77,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
content := []byte(textPlainDockerfile)
ct := "text/plain"
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bReader, err := inspectResponse(ct, br, int64(len(content)))
contentType, bReader, err := inspectResponse(ct, br, len(content))
if err != nil {
t.Fatal(err)
}
@@ -96,7 +96,7 @@ func TestInspectResponseTextSimple(t *testing.T) {
func TestInspectResponseEmptyContentType(t *testing.T) {
content := []byte(textPlainDockerfile)
br := ioutil.NopCloser(bytes.NewReader(content))
contentType, bodyReader, err := inspectResponse("", br, int64(len(content)))
contentType, bodyReader, err := inspectResponse("", br, len(content))
if err != nil {
t.Fatal(err)
}
-5
View File
@@ -232,11 +232,6 @@ func parseString(rest string) (*Node, map[string]bool, error) {
// parseJSON converts JSON arrays to an AST.
func parseJSON(rest string) (*Node, map[string]bool, error) {
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
if !strings.HasPrefix(rest, "[") {
return nil, nil, fmt.Errorf(`Error parsing "%s" as a JSON array`, rest)
}
var myJSON []interface{}
if err := json.NewDecoder(strings.NewReader(rest)).Decode(&myJSON); err != nil {
return nil, nil, err
+1 -1
View File
@@ -42,7 +42,7 @@ var (
func init() {
// Dispatch Table. see line_parsers.go for the parse functions.
// The command is parsed and mapped to the line parser. The line parser
// receives the arguments but not the command, and returns an AST after
// recieves the arguments but not the command, and returns an AST after
// reformulating the arguments according to the rules in the parser
// functions. Errors are propagated up by Parse() and the resulting AST can
// be incorporated directly into the existing AST as a next.
@@ -3,8 +3,6 @@ MAINTAINER Seongyeol Lim <seongyeol37@gmail.com>
COPY . /go/src/github.com/docker/docker
ADD . /
ADD null /
COPY nullfile /tmp
ADD [ "vimrc", "/tmp" ]
COPY [ "bashrc", "/tmp" ]
COPY [ "test file", "/tmp" ]
@@ -2,8 +2,6 @@
(maintainer "Seongyeol Lim <seongyeol37@gmail.com>")
(copy "." "/go/src/github.com/docker/docker")
(add "." "/")
(add "null" "/")
(copy "nullfile" "/tmp")
(add "vimrc" "/tmp")
(copy "bashrc" "/tmp")
(copy "test file" "/tmp")
-42
View File
@@ -49,45 +49,3 @@ func TestShellParser(t *testing.T) {
}
}
}
func TestGetEnv(t *testing.T) {
sw := &shellWord{
word: "",
envs: nil,
pos: 0,
}
sw.envs = []string{}
if sw.getEnv("foo") != "" {
t.Fatalf("2 - 'foo' should map to ''")
}
sw.envs = []string{"foo"}
if sw.getEnv("foo") != "" {
t.Fatalf("3 - 'foo' should map to ''")
}
sw.envs = []string{"foo="}
if sw.getEnv("foo") != "" {
t.Fatalf("4 - 'foo' should map to ''")
}
sw.envs = []string{"foo=bar"}
if sw.getEnv("foo") != "bar" {
t.Fatalf("5 - 'foo' should map to 'bar'")
}
sw.envs = []string{"foo=bar", "car=hat"}
if sw.getEnv("foo") != "bar" {
t.Fatalf("6 - 'foo' should map to 'bar'")
}
if sw.getEnv("car") != "hat" {
t.Fatalf("7 - 'car' should map to 'hat'")
}
// Make sure we grab the first 'car' in the list
sw.envs = []string{"foo=bar", "car=hat", "car=bike"}
if sw.getEnv("car") != "hat" {
t.Fatalf("8 - 'car' should map to 'hat'")
}
}
+59 -106
View File
@@ -4,7 +4,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -15,7 +14,7 @@ import (
)
const (
// ConfigFileName is the name of config file
// ConfigFile is the name of config file
ConfigFileName = "config.json"
oldConfigfile = ".dockercfg"
@@ -71,88 +70,6 @@ func NewConfigFile(fn string) *ConfigFile {
}
}
// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
// auth config information with given directory and populates the receiver object
func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
b, err := ioutil.ReadAll(configData)
if err != nil {
return err
}
if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return fmt.Errorf("The Auth config file is empty")
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return fmt.Errorf("Invalid Auth config file")
}
authConfig.Username, authConfig.Password, err = DecodeAuth(origAuth[1])
if err != nil {
return err
}
origEmail := strings.Split(arr[1], " = ")
if len(origEmail) != 2 {
return fmt.Errorf("Invalid Auth config file")
}
authConfig.Email = origEmail[1]
authConfig.ServerAddress = defaultIndexserver
configFile.AuthConfigs[defaultIndexserver] = authConfig
} else {
for k, authConfig := range configFile.AuthConfigs {
authConfig.Username, authConfig.Password, err = DecodeAuth(authConfig.Auth)
if err != nil {
return err
}
authConfig.Auth = ""
authConfig.ServerAddress = k
configFile.AuthConfigs[k] = authConfig
}
}
return nil
}
// LoadFromReader reads the configuration data given and sets up the auth config
// information with given directory and populates the receiver object
func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
return err
}
var err error
for addr, ac := range configFile.AuthConfigs {
ac.Username, ac.Password, err = DecodeAuth(ac.Auth)
if err != nil {
return err
}
ac.Auth = ""
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
return nil
}
// LegacyLoadFromReader is a convenience function that creates a ConfigFile object from
// a non-nested reader
func LegacyLoadFromReader(configData io.Reader) (*ConfigFile, error) {
configFile := ConfigFile{
AuthConfigs: make(map[string]AuthConfig),
}
err := configFile.LegacyLoadFromReader(configData)
return &configFile, err
}
// LoadFromReader is a convenience function that creates a ConfigFile object from
// a reader
func LoadFromReader(configData io.Reader) (*ConfigFile, error) {
configFile := ConfigFile{
AuthConfigs: make(map[string]AuthConfig),
}
err := configFile.LoadFromReader(configData)
return &configFile, err
}
// Load reads the configuration files in the given directory, and sets up
// the auth config information and return values.
// FIXME: use the internal golang config parser
@@ -173,8 +90,22 @@ func Load(configDir string) (*ConfigFile, error) {
return &configFile, err
}
defer file.Close()
err = configFile.LoadFromReader(file)
return &configFile, err
if err := json.NewDecoder(file).Decode(&configFile); err != nil {
return &configFile, err
}
for addr, ac := range configFile.AuthConfigs {
ac.Username, ac.Password, err = DecodeAuth(ac.Auth)
if err != nil {
return &configFile, err
}
ac.Auth = ""
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
return &configFile, nil
} else if !os.IsNotExist(err) {
// if file is there but we can't stat it for any reason other
// than it doesn't exist then stop
@@ -186,18 +117,49 @@ func Load(configDir string) (*ConfigFile, error) {
if _, err := os.Stat(confFile); err != nil {
return &configFile, nil //missing file is not an error
}
file, err := os.Open(confFile)
b, err := ioutil.ReadFile(confFile)
if err != nil {
return &configFile, err
}
defer file.Close()
err = configFile.LegacyLoadFromReader(file)
return &configFile, err
if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
arr := strings.Split(string(b), "\n")
if len(arr) < 2 {
return &configFile, fmt.Errorf("The Auth config file is empty")
}
authConfig := AuthConfig{}
origAuth := strings.Split(arr[0], " = ")
if len(origAuth) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Username, authConfig.Password, err = DecodeAuth(origAuth[1])
if err != nil {
return &configFile, err
}
origEmail := strings.Split(arr[1], " = ")
if len(origEmail) != 2 {
return &configFile, fmt.Errorf("Invalid Auth config file")
}
authConfig.Email = origEmail[1]
authConfig.ServerAddress = defaultIndexserver
configFile.AuthConfigs[defaultIndexserver] = authConfig
} else {
for k, authConfig := range configFile.AuthConfigs {
authConfig.Username, authConfig.Password, err = DecodeAuth(authConfig.Auth)
if err != nil {
return &configFile, err
}
authConfig.Auth = ""
authConfig.ServerAddress = k
configFile.AuthConfigs[k] = authConfig
}
}
return &configFile, nil
}
// SaveToWriter encodes and writes out all the authorization information to
// the given writer
func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() error {
// Encode sensitive data into a new/temp struct
tmpAuthConfigs := make(map[string]AuthConfig, len(configFile.AuthConfigs))
for k, authConfig := range configFile.AuthConfigs {
@@ -218,25 +180,16 @@ func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
if err != nil {
return err
}
_, err = writer.Write(data)
return err
}
// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() error {
if configFile.Filename() == "" {
return fmt.Errorf("Can't save config with empty filename")
}
if err := system.MkdirAll(filepath.Dir(configFile.filename), 0700); err != nil {
return err
}
f, err := os.OpenFile(configFile.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
if err := ioutil.WriteFile(configFile.filename, data, 0600); err != nil {
return err
}
defer f.Close()
return configFile.SaveToWriter(f)
return nil
}
// Filename returns the name of the configuration file
+92 -362
View File
@@ -4,41 +4,15 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/docker/docker/pkg/homedir"
)
func TestEmptyConfigDir(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
SetConfigDir(tmpHome)
config, err := Load("")
if err != nil {
t.Fatalf("Failed loading on empty config dir: %q", err)
}
expectedConfigFilename := filepath.Join(tmpHome, ConfigFileName)
if config.Filename() != expectedConfigFilename {
t.Fatalf("Expected config filename %s, got %s", expectedConfigFilename, config.Filename())
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
}
func TestMissingFile(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
config, err := Load(tmpHome)
if err != nil {
@@ -46,15 +20,19 @@ func TestMissingFile(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestSaveFileToDirs(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
tmpHome += "/.docker"
@@ -64,38 +42,32 @@ func TestSaveFileToDirs(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestEmptyFile(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
if err := ioutil.WriteFile(fn, []byte(""), 0600); err != nil {
t.Fatal(err)
}
ioutil.WriteFile(fn, []byte(""), 0600)
_, err = Load(tmpHome)
_, err := Load(tmpHome)
if err == nil {
t.Fatalf("Was supposed to fail")
}
}
func TestEmptyJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
if err := ioutil.WriteFile(fn, []byte("{}"), 0600); err != nil {
t.Fatal(err)
}
ioutil.WriteFile(fn, []byte("{}"), 0600)
config, err := Load(tmpHome)
if err != nil {
@@ -103,276 +75,36 @@ func TestEmptyJson(t *testing.T) {
}
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat(t, config, tmpHome)
}
func TestOldInvalidsAuth(t *testing.T) {
invalids := map[string]string{
`username = test`: "The Auth config file is empty",
`username
password
email`: "Invalid Auth config file",
`username = test
email`: "Invalid auth configuration file",
`username = am9lam9lOmhlbGxv
email`: "Invalid Auth config file",
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
for content, expectedError := range invalids {
fn := filepath.Join(tmpHome, oldConfigfile)
if err := ioutil.WriteFile(fn, []byte(content), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err == nil || err.Error() != expectedError {
t.Fatalf("Should have failed, got: %q, %q", config, err)
}
}
}
func TestOldValidAuth(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `username = am9lam9lOmhlbGxv
email = user@example.com`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatal(err)
}
// defaultIndexserver is https://index.docker.io/v1/
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestOldJsonInvalid(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"test","email":"user@example.com"}}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err == nil || err.Error() != "Invalid auth configuration file" {
t.Fatalf("Expected an error got : %v, %v", config, err)
}
}
func TestOldJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
homeKey := homedir.Key()
homeVal := homedir.Get()
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestNewJson(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, "user@example.com") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
func TestJsonWithPsFormat(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
t.Fatal(err)
}
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
if config.PsFormat != `table {{.ID}}\t{{.Label "com.docker.label.cpu"}}` {
t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
if !strings.Contains(configStr, `"psFormat":`) ||
!strings.Contains(configStr, "{{.ID}}") {
t.Fatalf("Should have save in new form: %s", configStr)
}
}
// Save it and make sure it shows up in new form
func saveConfigAndValidateNewFormat(t *testing.T, config *ConfigFile, homeFolder string) string {
err := config.Save()
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(homeFolder, ConfigFileName))
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) {
t.Fatalf("Should have save in new form: %s", string(buf))
}
return string(buf)
}
func TestConfigDir(t *testing.T) {
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatal(err)
func TestOldJson(t *testing.T) {
if runtime.GOOS == "windows" {
return
}
tmpHome, _ := ioutil.TempDir("", "config-test")
defer os.RemoveAll(tmpHome)
if ConfigDir() == tmpHome {
t.Fatalf("Expected ConfigDir to be different than %s by default, but was the same", tmpHome)
}
homeKey := homedir.Key()
homeVal := homedir.Get()
// Update configDir
SetConfigDir(tmpHome)
defer func() { os.Setenv(homeKey, homeVal) }()
os.Setenv(homeKey, tmpHome)
if ConfigDir() != tmpHome {
t.Fatalf("Expected ConfigDir to %s, but was %s", tmpHome, ConfigDir())
}
}
func TestConfigFile(t *testing.T) {
configFilename := "configFilename"
configFile := NewConfigFile(configFilename)
if configFile.Filename() != configFilename {
t.Fatalf("Expected %s, got %s", configFilename, configFile.Filename())
}
}
func TestJsonReaderNoFile(t *testing.T) {
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
config, err := LoadFromReader(strings.NewReader(js))
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
}
func TestOldJsonReaderNoFile(t *testing.T) {
fn := filepath.Join(tmpHome, oldConfigfile)
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := LegacyLoadFromReader(strings.NewReader(js))
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
@@ -381,14 +113,59 @@ func TestOldJsonReaderNoFile(t *testing.T) {
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestJsonWithPsFormatNoFile(t *testing.T) {
func TestNewJson(t *testing.T) {
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
ac := config.AuthConfigs["https://index.docker.io/v1/"]
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
t.Fatalf("Missing data from parsing:\n%q", config)
}
// Now save it and make sure it shows up in new form
err = config.Save()
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestJsonWithPsFormat(t *testing.T) {
tmpHome, _ := ioutil.TempDir("", "config-test")
fn := filepath.Join(tmpHome, ConfigFileName)
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
config, err := LoadFromReader(strings.NewReader(js))
ioutil.WriteFile(fn, []byte(js), 0600)
config, err := Load(tmpHome)
if err != nil {
t.Fatalf("Failed loading on empty json file: %q", err)
}
@@ -397,62 +174,15 @@ func TestJsonWithPsFormatNoFile(t *testing.T) {
t.Fatalf("Unknown ps format: %s\n", config.PsFormat)
}
}
func TestJsonSaveWithNoFile(t *testing.T) {
js := `{
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
}`
config, err := LoadFromReader(strings.NewReader(js))
// Now save it and make sure it shows up in new form
err = config.Save()
if err == nil {
t.Fatalf("Expected error. File should not have been able to save with no file name.")
if err != nil {
t.Fatalf("Failed to save: %q", err)
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatalf("Failed to create a temp dir: %q", err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
err = config.SaveToWriter(f)
if err != nil {
t.Fatalf("Failed saving to file: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
func TestLegacyJsonSaveWithNoFile(t *testing.T) {
js := `{"https://index.docker.io/v1/":{"auth":"am9lam9lOmhlbGxv","email":"user@example.com"}}`
config, err := LegacyLoadFromReader(strings.NewReader(js))
err = config.Save()
if err == nil {
t.Fatalf("Expected error. File should not have been able to save with no file name.")
}
tmpHome, err := ioutil.TempDir("", "config-test")
if err != nil {
t.Fatalf("Failed to create a temp dir: %q", err)
}
defer os.RemoveAll(tmpHome)
fn := filepath.Join(tmpHome, ConfigFileName)
f, _ := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
err = config.SaveToWriter(f)
if err != nil {
t.Fatalf("Failed saving to file: %q", err)
}
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
if !strings.Contains(string(buf), `"auths":`) ||
!strings.Contains(string(buf), "user@example.com") {
if !strings.Contains(string(buf), `"psFormat":`) ||
!strings.Contains(string(buf), "{{.ID}}") {
t.Fatalf("Should have save in new form: %s", string(buf))
}
}
+25
View File
@@ -0,0 +1,25 @@
#include <tunables/global>
profile docker-default flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network,
capability,
file,
umount,
deny @{PROC}/sys/fs/** wklx,
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx,
deny @{PROC}/sys/kernel/*/** wklx,
deny mount,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/[^c]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/fs/cg[^r]*/** wklx,
deny /sys/firmware/efi/efivars/** rwklx,
deny /sys/kernel/security/** rwklx,
}
+28 -167
View File
@@ -1,6 +1,6 @@
@{DOCKER_GRAPH_PATH}=/var/lib/docker
profile /usr/bin/docker (attach_disconnected, complain) {
profile /usr/bin/docker (attach_disconnected) {
# Prevent following links to these files during container setup.
deny /etc/** mkl,
deny /dev/** kl,
@@ -21,190 +21,51 @@ profile /usr/bin/docker (attach_disconnected, complain) {
ipc rw,
network,
capability,
owner /** rw,
/var/lib/docker/** rwl,
# For non-root client use:
/dev/urandom r,
/run/docker.sock rw,
/proc/** r,
/sys/kernel/mm/hugepages/ r,
/etc/localtime r,
file,
ptrace peer=@{profile_name},
ptrace (read) peer=docker-default,
deny ptrace (trace) peer=docker-default,
deny ptrace peer=/usr/bin/docker///bin/ps,
/usr/bin/docker pix,
/sbin/xtables-multi rCx,
/sbin/xtables-multi rCix,
/sbin/iptables rCx,
/sbin/modprobe rCx,
/sbin/auplink rCx,
/sbin/mke2fs rCx,
/sbin/tune2fs rCx,
/sbin/blkid rCx,
/bin/kmod rCx,
/usr/bin/xz rCx,
/bin/ps rCx,
/bin/cat rCx,
/sbin/zfs rCx,
# Transitions
change_profile -> docker-*,
change_profile -> unconfined,
profile /bin/cat (complain) {
/etc/ld.so.cache r,
/lib/** r,
/dev/null rw,
/proc r,
/bin/cat mr,
# For reading in 'docker stats':
/proc/[0-9]*/net/dev r,
profile /sbin/iptables {
signal (receive) peer=/usr/bin/docker,
capability net_admin,
}
profile /bin/ps (complain) {
/etc/ld.so.cache r,
/etc/localtime r,
/etc/passwd r,
/etc/nsswitch.conf r,
/lib/** r,
/proc/[0-9]*/** r,
/dev/null rw,
/bin/ps mr,
profile /sbin/auplink flags=(attach_disconnected) {
signal (receive) peer=/usr/bin/docker,
capability sys_admin,
capability dac_override,
# We don't need ptrace so we'll deny and ignore the error.
deny ptrace (read, trace),
@{DOCKER_GRAPH_PATH}/aufs/** rw,
# For user namespaces:
@{DOCKER_GRAPH_PATH}/[0-9]*.[0-9]*/** rw,
# Quiet dac_override denials
deny capability dac_override,
deny capability dac_read_search,
deny capability sys_ptrace,
/dev/tty r,
/proc/stat r,
/proc/cpuinfo r,
/proc/meminfo r,
/proc/uptime r,
/sys/devices/system/cpu/online r,
/proc/sys/kernel/pid_max r,
/proc/ r,
/proc/tty/drivers r,
# The following may be removed via delegates
/sys/fs/aufs/** r,
/lib/** r,
/apparmor/.null r,
/dev/null rw,
/etc/ld.so.cache r,
/sbin/auplink rm,
/proc/fs/aufs/** rw,
/proc/[0-9]*/mounts rw,
}
profile /sbin/iptables (complain) {
signal (receive) peer=/usr/bin/docker,
capability net_admin,
}
profile /sbin/auplink flags=(attach_disconnected, complain) {
signal (receive) peer=/usr/bin/docker,
capability sys_admin,
capability dac_override,
@{DOCKER_GRAPH_PATH}/aufs/** rw,
@{DOCKER_GRAPH_PATH}/tmp/** rw,
# For user namespaces:
@{DOCKER_GRAPH_PATH}/[0-9]*.[0-9]*/** rw,
/sys/fs/aufs/** r,
/lib/** r,
/apparmor/.null r,
/dev/null rw,
/etc/ld.so.cache r,
/sbin/auplink rm,
/proc/fs/aufs/** rw,
/proc/[0-9]*/mounts rw,
}
profile /sbin/modprobe /bin/kmod (complain) {
signal (receive) peer=/usr/bin/docker,
capability sys_module,
/etc/ld.so.cache r,
/lib/** r,
/dev/null rw,
/apparmor/.null rw,
/sbin/modprobe rm,
/bin/kmod rm,
/proc/cmdline r,
/sys/module/** r,
/etc/modprobe.d{/,/**} r,
profile /sbin/modprobe {
signal (receive) peer=/usr/bin/docker,
capability sys_module,
file,
}
# xz works via pipes, so we do not need access to the filesystem.
profile /usr/bin/xz (complain) {
signal (receive) peer=/usr/bin/docker,
/etc/ld.so.cache r,
/lib/** r,
/usr/bin/xz rm,
deny /proc/** rw,
deny /sys/** rw,
}
profile /sbin/xtables-multi (attach_disconnected, complain) {
/etc/ld.so.cache r,
/lib/** r,
/sbin/xtables-multi rm,
/apparmor/.null w,
/dev/null rw,
capability net_raw,
capability net_admin,
network raw,
}
profile /sbin/zfs (attach_disconnected, complain) {
file,
capability,
}
profile /sbin/mke2fs (complain) {
/sbin/mke2fs rm,
/lib/** r,
/apparmor/.null w,
/etc/ld.so.cache r,
/etc/mke2fs.conf r,
/etc/mtab r,
/dev/dm-* rw,
/dev/urandom r,
/dev/null rw,
/proc/swaps r,
/proc/[0-9]*/mounts r,
}
profile /sbin/tune2fs (complain) {
/sbin/tune2fs rm,
/lib/** r,
/apparmor/.null w,
/etc/blkid.conf r,
/etc/mtab r,
/etc/ld.so.cache r,
/dev/null rw,
/dev/.blkid.tab r,
/dev/dm-* rw,
/proc/swaps r,
/proc/[0-9]*/mounts r,
}
profile /sbin/blkid (complain) {
/sbin/blkid rm,
/lib/** r,
/apparmor/.null w,
/etc/ld.so.cache r,
/etc/blkid.conf r,
/dev/null rw,
/dev/.blkid.tab rl,
/dev/.blkid.tab* rwl,
/dev/dm-* r,
/sys/devices/virtual/block/** r,
capability mknod,
mount -> @{DOCKER_GRAPH_PATH}/**,
profile /usr/bin/xz {
signal (receive) peer=/usr/bin/docker,
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
FROM debian:jessie
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -4,7 +4,7 @@
FROM debian:stretch
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+3 -2
View File
@@ -2,9 +2,10 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM debian:wheezy-backports
FROM debian:wheezy
RUN echo deb http://http.debian.net/debian wheezy-backports main > /etc/apt/sources.list.d/wheezy-backports.list
RUN apt-get update && apt-get install -y bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+8 -13
View File
@@ -22,13 +22,6 @@ for version in "${versions[@]}"; do
suite="${version##*-}"
from="${distro}:${suite}"
case "$from" in
debian:wheezy)
# add -backports, like our users have to
from+='-backports'
;;
esac
mkdir -p "$version"
echo "$version -> FROM $from"
cat > "$version/Dockerfile" <<-EOF
@@ -39,6 +32,13 @@ for version in "${versions[@]}"; do
FROM $from
EOF
case "$from" in
debian:wheezy)
# add -backports, like our users have to
echo "RUN echo deb http://http.debian.net/debian $suite-backports main > /etc/apt/sources.list.d/$suite-backports.list" >> "$version/Dockerfile"
;;
esac
echo >> "$version/Dockerfile"
extraBuildTags=
@@ -50,6 +50,7 @@ for version in "${versions[@]}"; do
build-essential # "essential for building Debian packages"
curl ca-certificates # for downloading Go
debhelper # for easy ".deb" building
dh-apparmor # for apparmor debhelper
dh-systemd # for systemd debhelper integration
git # for "git commit" info in "docker -v"
libapparmor-dev # for "sys/apparmor.h"
@@ -73,12 +74,6 @@ for version in "${versions[@]}"; do
extraBuildTags+=' exclude_graphdriver_btrfs'
fi
if [ "$suite" = 'wheezy' ]; then
# pull btrfs-toold from backports
backports="/$suite-backports"
packages=( "${packages[@]/btrfs-tools/btrfs-tools$backports}" )
fi
echo "RUN apt-get update && apt-get install -y ${packages[*]} --no-install-recommends && rm -rf /var/lib/apt/lists/*" >> "$version/Dockerfile"
echo >> "$version/Dockerfile"
@@ -2,9 +2,9 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:precise
FROM ubuntu-debootstrap:precise
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper dh-apparmor git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -2,9 +2,9 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:trusty
FROM ubuntu-debootstrap:trusty
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -2,9 +2,9 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:vivid
FROM ubuntu-debootstrap:vivid
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -2,9 +2,9 @@
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
#
FROM ubuntu:wily
FROM ubuntu-debootstrap:wily
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+1 -1
View File
@@ -6,7 +6,7 @@ FROM centos:7
RUN yum groupinstall -y "Development Tools"
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+15
View File
@@ -0,0 +1,15 @@
#
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/generate.sh"!
#
FROM fedora:20
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux
+1 -1
View File
@@ -5,7 +5,7 @@
FROM fedora:21
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+1 -1
View File
@@ -5,7 +5,7 @@
FROM fedora:22
RUN yum install -y @development-tools fedora-packager
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
-2
View File
@@ -58,8 +58,6 @@ for version in "${versions[@]}"; do
device-mapper-devel # for "libdevmapper.h"
glibc-static
libselinux-devel # for "libselinux.so"
selinux-policy
selinux-policy-devel
sqlite-devel # for "sqlite3.h"
tar # older versions of dev-tools do not have tar
)
+1 -1
View File
@@ -5,7 +5,7 @@
FROM oraclelinux:6
RUN yum groupinstall -y "Development Tools"
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+1 -1
View File
@@ -5,7 +5,7 @@
FROM oraclelinux:7
RUN yum groupinstall -y "Development Tools"
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel sqlite-devel tar
ENV GO_VERSION 1.4.2
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
+2 -8
View File
@@ -191,17 +191,11 @@ if [ "$kernelMajor" -lt 3 ] || [ "$kernelMajor" -eq 3 -a "$kernelMinor" -le 18 ]
check_flags RESOURCE_COUNTERS
fi
if [ "$kernelMajor" -lt 3 ] || [ "$kernelMajor" -eq 3 -a "$kernelMinor" -le 13 ]; then
netprio=NETPRIO_CGROUP
else
netprio=CGROUP_NET_PRIO
fi
flags=(
BLK_CGROUP IOSCHED_CFQ BLK_DEV_THROTTLING
BLK_CGROUP IOSCHED_CFQ
CGROUP_PERF
CGROUP_HUGETLB
NET_CLS_CGROUP $netprio
NET_CLS_CGROUP NETPRIO_CGROUP
CFS_BANDWIDTH FAIR_GROUP_SCHED RT_GROUP_SCHED
)
check_flags "${flags[@]}"
Regular → Executable
+92 -255
View File
@@ -14,22 +14,6 @@
# - copy this file to e.g. ~/.docker-completion.sh and add the line
# below to your .bashrc after bash completion features are loaded
# . ~/.docker-completion.sh
#
# Configuration:
#
# You can tailor completion for the "events", "history", "inspect", "run",
# "rmi" and "save" commands by settings the following environment
# variables:
#
# DOCKER_COMPLETION_SHOW_IMAGE_IDS
# "none" - Show names only (default)
# "non-intermediate" - Show names and ids, but omit intermediate image IDs
# "all" - Show names and ids, including intermediate image IDs
#
# DOCKER_COMPLETION_SHOW_TAGS
# "yes" - include tags in completion options (default)
# "no" - don't include tags in completion options
#
# Note:
# Currently, the completions will not work if the docker daemon is not
@@ -43,7 +27,7 @@
# This order should be applied to lists, alternatives and code blocks.
__docker_q() {
docker ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@"
docker ${host:+-H "$host"} 2>/dev/null "$@"
}
__docker_containers_all() {
@@ -86,40 +70,6 @@ __docker_container_ids() {
COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") )
}
__docker_images() {
local images_args=""
case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in
all)
images_args="--no-trunc -a"
;;
non-intermediate)
images_args="--no-trunc"
;;
esac
local repo_print_command
if [ "${DOCKER_COMPLETION_SHOW_TAGS:-yes}" = "yes" ]; then
repo_print_command='print $1; print $1":"$2'
else
repo_print_command='print $1'
fi
local awk_script
case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in
all|non-intermediate)
awk_script='NR>1 { print $3; if ($1 != "<none>") { '"$repo_print_command"' } }'
;;
none|*)
awk_script='NR>1 && $1 != "<none>" { '"$repo_print_command"' }'
;;
esac
local images=$(__docker_q images $images_args | awk "$awk_script")
COMPREPLY=( $(compgen -W "$images" -- "$cur") )
__ltrim_colon_completions "$cur"
}
__docker_image_repos() {
local repos="$(__docker_q images | awk 'NR>1 && $1 != "<none>" { print $1 }')"
COMPREPLY=( $(compgen -W "$repos" -- "$cur") )
@@ -131,10 +81,16 @@ __docker_image_repos_and_tags() {
__ltrim_colon_completions "$cur"
}
__docker_image_repos_and_tags_and_ids() {
local images="$(__docker_q images -a --no-trunc | awk 'NR>1 { print $3; if ($1 != "<none>") { print $1; print $1":"$2 } }')"
COMPREPLY=( $(compgen -W "$images" -- "$cur") )
__ltrim_colon_completions "$cur"
}
__docker_containers_and_images() {
__docker_containers_all
local containers=( "${COMPREPLY[@]}" )
__docker_images
__docker_image_repos_and_tags_and_ids
COMPREPLY+=( "${containers[@]}" )
}
@@ -183,7 +139,7 @@ __docker_value_of_option() {
local counter=$((command_pos + 1))
while [ $counter -lt $cword ]; do
case ${words[$counter]} in
@($option_glob) )
$option_glob )
echo ${words[$counter + 1]}
break
;;
@@ -273,12 +229,11 @@ __docker_log_driver_options() {
# see docs/reference/logging/index.md
local fluentd_options="fluentd-address fluentd-tag"
local gelf_options="gelf-address gelf-tag"
local json_file_options="max-file max-size"
local syslog_options="syslog-address syslog-facility syslog-tag"
case $(__docker_value_of_option --log-driver) in
'')
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $json_file_options $syslog_options" -S = -- "$cur" ) )
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $syslog_options" -S = -- "$cur" ) )
;;
fluentd)
COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) )
@@ -286,9 +241,6 @@ __docker_log_driver_options() {
gelf)
COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) )
;;
json-file)
COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) )
;;
syslog)
COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) )
;;
@@ -343,10 +295,6 @@ __docker_complete_log_driver_options() {
return 1
}
__docker_log_levels() {
COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) )
}
# a selection of the available signals that is most likely of interest in the
# context of docker containers.
__docker_signals() {
@@ -364,34 +312,61 @@ __docker_signals() {
COMPREPLY=( $( compgen -W "${signals[*]} ${signals[*]#SIG}" -- "$( echo $cur | tr '[:lower:]' '[:upper:]')" ) )
}
# global options that may appear after the docker command
_docker_docker() {
local boolean_options="
$global_boolean_options
--help
--daemon -d
--debug -D
--help -h
--icc
--ip-forward
--ip-masq
--iptables
--ipv6
--selinux-enabled
--tls
--tlsverify
--userland-proxy=false
--version -v
"
case "$prev" in
--config)
--exec-root|--graph|-g)
_filedir -d
return
;;
--log-level|-l)
__docker_log_levels
--log-driver)
__docker_log_drivers
return
;;
$(__docker_to_extglob "$global_options_with_args") )
--log-level|-l)
COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) )
return
;;
--log-opt)
__docker_log_driver_options
return
;;
--pidfile|-p|--tlscacert|--tlscert|--tlskey)
_filedir
return
;;
--storage-driver|-s)
COMPREPLY=( $( compgen -W "aufs devicemapper btrfs overlay" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
return
;;
$main_options_with_args_glob )
return
;;
esac
__docker_complete_log_driver_options && return
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "$boolean_options $global_options_with_args" -- "$cur" ) )
COMPREPLY=( $( compgen -W "$boolean_options $main_options_with_args" -- "$cur" ) )
;;
*)
local counter=$( __docker_pos_first_nonflag $(__docker_to_extglob "$global_options_with_args") )
local counter="$(__docker_pos_first_nonflag $main_options_with_args_glob)"
if [ $cword -eq $counter ]; then
COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) )
fi
@@ -503,138 +478,6 @@ _docker_create() {
_docker_run
}
_docker_daemon() {
local boolean_options="
$global_boolean_options
--help
--icc=false
--ip-forward=false
--ip-masq=false
--iptables=false
--ipv6
--selinux-enabled
--userland-proxy=false
"
local options_with_args="
$global_options_with_args
--api-cors-header
--bip
--bridge -b
--default-gateway
--default-gateway-v6
--default-ulimit
--dns
--dns-search
--exec-driver -e
--exec-opt
--exec-root
--fixed-cidr
--fixed-cidr-v6
--graph -g
--group -G
--insecure-registry
--ip
--label
--log-driver
--log-opt
--mtu
--pidfile -p
--registry-mirror
--storage-driver -s
--storage-opt
"
case "$prev" in
--exec-root|--graph|-g)
_filedir -d
return
;;
--log-driver)
__docker_log_drivers
return
;;
--pidfile|-p|--tlscacert|--tlscert|--tlskey)
_filedir
return
;;
--storage-driver|-s)
COMPREPLY=( $( compgen -W "aufs btrfs devicemapper overlay vfs zfs" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
return
;;
--storage-opt)
local devicemapper_options="
dm.basesize
dm.blkdiscard
dm.blocksize
dm.fs
dm.loopdatasize
dm.loopmetadatasize
dm.mkfsarg
dm.mountopt
dm.override_udev_sync_check
dm.thinpooldev
"
local zfs_options="zfs.fsname"
case $(__docker_value_of_option '--storage-driver|-s') in
'')
COMPREPLY=( $( compgen -W "$devicemapper_options $zfs_options" -S = -- "$cur" ) )
;;
devicemapper)
COMPREPLY=( $( compgen -W "$devicemapper_options" -S = -- "$cur" ) )
;;
zfs)
COMPREPLY=( $( compgen -W "$zfs_options" -S = -- "$cur" ) )
;;
*)
return
;;
esac
compopt -o nospace
return
;;
--log-level|-l)
__docker_log_levels
return
;;
--log-opt)
__docker_log_driver_options
return
;;
$(__docker_to_extglob "$options_with_args") )
return
;;
esac
__docker_complete_log_driver_options && return
# completions for --storage-opt
case "${words[$cword-2]}$prev=" in
*dm.blkdiscard=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
*dm.fs=*)
COMPREPLY=( $( compgen -W "ext4 xfs" -- "${cur#=}" ) )
return
;;
*dm.override_udev_sync_check=*)
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
return
;;
*dm.thinpooldev=*)
_filedir
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
;;
esac
}
_docker_diff() {
case "$cur" in
-*)
@@ -699,7 +542,7 @@ _docker_events() {
;;
*image=*)
cur="${cur#=}"
__docker_images
__docker_image_repos_and_tags_and_ids
return
;;
esac
@@ -720,7 +563,7 @@ _docker_exec() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i -t --tty -u --user" -- "$cur" ) )
;;
*)
__docker_containers_running
@@ -757,7 +600,7 @@ _docker_history() {
*)
local counter=$(__docker_pos_first_nonflag)
if [ $cword -eq $counter ]; then
__docker_images
__docker_image_repos_and_tags_and_ids
fi
;;
esac
@@ -842,17 +685,8 @@ _docker_inspect() {
COMPREPLY=( $( compgen -W "--format -f --type --help" -- "$cur" ) )
;;
*)
case $(__docker_value_of_option --type) in
'')
__docker_containers_and_images
;;
container)
__docker_containers_all
;;
image)
__docker_images
;;
esac
__docker_containers_and_images
;;
esac
}
@@ -965,21 +799,16 @@ _docker_ps() {
__docker_containers_all
;;
--filter|-f)
COMPREPLY=( $( compgen -S = -W "ancestor exited id label name status" -- "$cur" ) )
COMPREPLY=( $( compgen -S = -W "exited id label name status" -- "$cur" ) )
compopt -o nospace
return
;;
--format|-n)
-n)
return
;;
esac
case "${words[$cword-2]}$prev=" in
*ancestor=*)
cur="${cur#=}"
__docker_images
return
;;
*id=*)
cur="${cur#=}"
__docker_container_ids
@@ -998,7 +827,7 @@ _docker_ps() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --format --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
;;
esac
}
@@ -1095,7 +924,7 @@ _docker_rmi() {
COMPREPLY=( $( compgen -W "--force -f --help --no-prune" -- "$cur" ) )
;;
*)
__docker_images
__docker_image_repos_and_tags_and_ids
;;
esac
}
@@ -1103,16 +932,15 @@ _docker_rmi() {
_docker_run() {
local options_with_args="
--add-host
--attach -a
--blkio-weight
--attach -a
--cap-add
--cap-drop
--cgroup-parent
--cidfile
--cpuset
--cpu-period
--cpu-quota
--cpuset-cpus
--cpuset-mems
--cpu-shares -c
--device
--dns
@@ -1124,9 +952,8 @@ _docker_run() {
--group-add
--hostname -h
--ipc
--kernel-memory
--label-file
--label -l
--label-file
--link
--log-driver
--log-opt
@@ -1134,15 +961,14 @@ _docker_run() {
--mac-address
--memory -m
--memory-swap
--memory-swappiness
--name
--net
--pid
--publish -p
--restart
--security-opt
--ulimit
--user -u
--ulimit
--uts
--volumes-from
--volume -v
@@ -1150,10 +976,8 @@ _docker_run() {
"
local all_options="$options_with_args
--disable-content-trust=false
--help
--interactive -i
--oom-kill-disable
--privileged
--publish-all -P
--read-only
@@ -1163,7 +987,7 @@ _docker_run() {
[ "$command" = "run" ] && all_options="$all_options
--detach -d
--rm
--sig-proxy=false
--sig-proxy
"
local options_with_args_glob=$(__docker_to_extglob "$options_with_args")
@@ -1305,8 +1129,9 @@ _docker_run() {
;;
*)
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
if [ $cword -eq $counter ]; then
__docker_images
__docker_image_repos_and_tags_and_ids
fi
;;
esac
@@ -1325,7 +1150,7 @@ _docker_save() {
COMPREPLY=( $( compgen -W "--help --output -o" -- "$cur" ) )
;;
*)
__docker_images
__docker_image_repos_and_tags_and_ids
;;
esac
}
@@ -1462,7 +1287,6 @@ _docker() {
commit
cp
create
daemon
diff
events
exec
@@ -1499,23 +1323,41 @@ _docker() {
wait
)
# These options are valid as global options for all client commands
# and valid as command options for `docker daemon`
local global_boolean_options="
--debug -D
--tls
--tlsverify
"
local global_options_with_args="
--config
local main_options_with_args="
--api-cors-header
--bip
--bridge -b
--default-gateway
--default-gateway-v6
--default-ulimit
--dns
--dns-search
--exec-driver -e
--exec-opt
--exec-root
--fixed-cidr
--fixed-cidr-v6
--graph -g
--group -G
--host -H
--insecure-registry
--ip
--label
--log-driver
--log-level -l
--log-opt
--mtu
--pidfile -p
--registry-mirror
--storage-driver -s
--storage-opt
--tlscacert
--tlscert
--tlskey
"
local host config
local main_options_with_args_glob=$(__docker_to_extglob "$main_options_with_args")
local host
COMPREPLY=()
local cur prev words cword
@@ -1530,12 +1372,7 @@ _docker() {
(( counter++ ))
host="${words[$counter]}"
;;
# save config so that completion can use custom configuration directories
--config)
(( counter++ ))
config="${words[$counter]}"
;;
$(__docker_to_extglob "$global_options_with_args") )
$main_options_with_args_glob )
(( counter++ ))
;;
-*)
+4 -4
View File
@@ -134,9 +134,9 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s i -l interac
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add link to another container in the form of <name|id>:alias'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
@@ -321,9 +321,9 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s i -l interactiv
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l ipc -d 'Default is to create a private IPC namespace (POSIX SysV IPC) for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add link to another container in the form of <name|id>:alias'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l lxc-conf -d '(lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number><optional unit>, where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g. 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number><optional unit>, where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
-502
View File
@@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
-16
View File
@@ -1,16 +0,0 @@
TARGETS?=docker
MODULES?=${TARGETS:=.pp.bz2}
SHAREDIR?=/usr/share
all: ${TARGETS:=.pp.bz2}
%.pp.bz2: %.pp
@echo Compressing $^ -\> $@
bzip2 -9 $^
%.pp: %.te
make -f ${SHAREDIR}/selinux/devel/Makefile $@
clean:
rm -f *~ *.tc *.pp *.pp.bz2
rm -rf tmp *.tar.gz
-24
View File
@@ -1,24 +0,0 @@
/root/\.docker gen_context(system_u:object_r:docker_home_t,s0)
/usr/bin/docker -- gen_context(system_u:object_r:docker_exec_t,s0)
/usr/lib/systemd/system/docker.service -- gen_context(system_u:object_r:docker_unit_file_t,s0)
/etc/docker(/.*)? gen_context(system_u:object_r:docker_config_t,s0)
/var/lib/docker(/.*)? gen_context(system_u:object_r:docker_var_lib_t,s0)
/var/lib/kublet(/.*)? gen_context(system_u:object_r:docker_var_lib_t,s0)
/var/lib/docker/vfs(/.*)? gen_context(system_u:object_r:svirt_sandbox_file_t,s0)
/var/run/docker\.pid -- gen_context(system_u:object_r:docker_var_run_t,s0)
/var/run/docker\.sock -s gen_context(system_u:object_r:docker_var_run_t,s0)
/var/run/docker-client(/.*)? gen_context(system_u:object_r:docker_var_run_t,s0)
/var/lock/lxc(/.*)? gen_context(system_u:object_r:docker_lock_t,s0)
/var/log/lxc(/.*)? gen_context(system_u:object_r:docker_log_t,s0)
/var/lib/docker/init(/.*)? gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/containers/.*/hosts gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/containers/.*/hostname gen_context(system_u:object_r:docker_share_t,s0)
/var/lib/docker/.*/config\.env gen_context(system_u:object_r:docker_share_t,s0)
-467
View File
@@ -1,467 +0,0 @@
## <summary>The open-source application container engine.</summary>
########################################
## <summary>
## Execute docker in the docker domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_domtrans',`
gen_require(`
type docker_t, docker_exec_t;
')
corecmd_search_bin($1)
domtrans_pattern($1, docker_exec_t, docker_t)
')
########################################
## <summary>
## Execute docker in the caller domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_exec',`
gen_require(`
type docker_exec_t;
')
corecmd_search_bin($1)
can_exec($1, docker_exec_t)
')
########################################
## <summary>
## Search docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_search_lib',`
gen_require(`
type docker_var_lib_t;
')
allow $1 docker_var_lib_t:dir search_dir_perms;
files_search_var_lib($1)
')
########################################
## <summary>
## Execute docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_exec_lib',`
gen_require(`
type docker_var_lib_t;
')
allow $1 docker_var_lib_t:dir search_dir_perms;
can_exec($1, docker_var_lib_t)
')
########################################
## <summary>
## Read docker lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_lib_files',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
read_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Read docker share files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_share_files',`
gen_require(`
type docker_share_t;
')
files_search_var_lib($1)
read_files_pattern($1, docker_share_t, docker_share_t)
')
########################################
## <summary>
## Manage docker lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_manage_lib_files',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
manage_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
manage_lnk_files_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Manage docker lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_manage_lib_dirs',`
gen_require(`
type docker_var_lib_t;
')
files_search_var_lib($1)
manage_dirs_pattern($1, docker_var_lib_t, docker_var_lib_t)
')
########################################
## <summary>
## Create objects in a docker var lib directory
## with an automatic type transition to
## a specified private type.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <param name="private_type">
## <summary>
## The type of the object to create.
## </summary>
## </param>
## <param name="object_class">
## <summary>
## The class of the object to be created.
## </summary>
## </param>
## <param name="name" optional="true">
## <summary>
## The name of the object being created.
## </summary>
## </param>
#
interface(`docker_lib_filetrans',`
gen_require(`
type docker_var_lib_t;
')
filetrans_pattern($1, docker_var_lib_t, $2, $3, $4)
')
########################################
## <summary>
## Read docker PID files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_read_pid_files',`
gen_require(`
type docker_var_run_t;
')
files_search_pids($1)
read_files_pattern($1, docker_var_run_t, docker_var_run_t)
')
########################################
## <summary>
## Execute docker server in the docker domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`docker_systemctl',`
gen_require(`
type docker_t;
type docker_unit_file_t;
')
systemd_exec_systemctl($1)
init_reload_services($1)
systemd_read_fifo_file_passwd_run($1)
allow $1 docker_unit_file_t:file read_file_perms;
allow $1 docker_unit_file_t:service manage_service_perms;
ps_process_pattern($1, docker_t)
')
########################################
## <summary>
## Read and write docker shared memory.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_rw_sem',`
gen_require(`
type docker_t;
')
allow $1 docker_t:sem rw_sem_perms;
')
#######################################
## <summary>
## Read and write the docker pty type.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_use_ptys',`
gen_require(`
type docker_devpts_t;
')
allow $1 docker_devpts_t:chr_file rw_term_perms;
')
#######################################
## <summary>
## Allow domain to create docker content
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_filetrans_named_content',`
gen_require(`
type docker_var_lib_t;
type docker_share_t;
type docker_log_t;
type docker_var_run_t;
type docker_home_t;
')
files_pid_filetrans($1, docker_var_run_t, file, "docker.pid")
files_pid_filetrans($1, docker_var_run_t, sock_file, "docker.sock")
files_pid_filetrans($1, docker_var_run_t, dir, "docker-client")
logging_log_filetrans($1, docker_log_t, dir, "lxc")
files_var_lib_filetrans($1, docker_var_lib_t, dir, "docker")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "config.env")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hosts")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "hostname")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, file, "resolv.conf")
filetrans_pattern($1, docker_var_lib_t, docker_share_t, dir, "init")
userdom_admin_home_dir_filetrans($1, docker_home_t, dir, ".docker")
')
########################################
## <summary>
## Connect to docker over a unix stream socket.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_stream_connect',`
gen_require(`
type docker_t, docker_var_run_t;
')
files_search_pids($1)
stream_connect_pattern($1, docker_var_run_t, docker_var_run_t, docker_t)
')
########################################
## <summary>
## Connect to SPC containers over a unix stream socket.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_spc_stream_connect',`
gen_require(`
type spc_t, spc_var_run_t;
')
files_search_pids($1)
files_write_all_pid_sockets($1)
allow $1 spc_t:unix_stream_socket connectto;
')
########################################
## <summary>
## All of the rules required to administrate
## an docker environment
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`docker_admin',`
gen_require(`
type docker_t;
type docker_var_lib_t, docker_var_run_t;
type docker_unit_file_t;
type docker_lock_t;
type docker_log_t;
type docker_config_t;
')
allow $1 docker_t:process { ptrace signal_perms };
ps_process_pattern($1, docker_t)
admin_pattern($1, docker_config_t)
files_search_var_lib($1)
admin_pattern($1, docker_var_lib_t)
files_search_pids($1)
admin_pattern($1, docker_var_run_t)
files_search_locks($1)
admin_pattern($1, docker_lock_t)
logging_search_logs($1)
admin_pattern($1, docker_log_t)
docker_systemctl($1)
admin_pattern($1, docker_unit_file_t)
allow $1 docker_unit_file_t:service all_service_perms;
optional_policy(`
systemd_passwd_agent_exec($1)
systemd_read_fifo_file_passwd_run($1)
')
')
interface(`domain_stub_named_filetrans_domain',`
gen_require(`
attribute named_filetrans_domain;
')
')
interface(`lvm_stub',`
gen_require(`
type lvm_t;
')
')
interface(`staff_stub',`
gen_require(`
type staff_t;
')
')
interface(`virt_stub_lxc',`
gen_require(`
type virtd_lxc_t;
')
')
interface(`virt_stub_svirt_sandbox_domain',`
gen_require(`
attribute svirt_sandbox_domain;
')
')
interface(`virt_stub_svirt_sandbox_file',`
gen_require(`
type svirt_sandbox_file_t;
')
')
interface(`fs_dontaudit_remount_tmpfs',`
gen_require(`
type tmpfs_t;
')
dontaudit $1 tmpfs_t:filesystem remount;
')
interface(`dev_dontaudit_list_all_dev_nodes',`
gen_require(`
type device_t;
')
dontaudit $1 device_t:dir list_dir_perms;
')
interface(`kernel_unlabeled_entry_type',`
gen_require(`
type unlabeled_t;
')
domain_entry_file($1, unlabeled_t)
')
interface(`kernel_unlabeled_domtrans',`
gen_require(`
type unlabeled_t;
')
read_lnk_files_pattern($1, unlabeled_t, unlabeled_t)
domain_transition_pattern($1, unlabeled_t, $2)
type_transition $1 unlabeled_t:process $2;
')
interface(`files_write_all_pid_sockets',`
gen_require(`
attribute pidfile;
')
allow $1 pidfile:sock_file write_sock_file_perms;
')
interface(`dev_dontaudit_mounton_sysfs',`
gen_require(`
type sysfs_t;
')
dontaudit $1 sysfs_t:dir mounton;
')
-418
View File
@@ -1,418 +0,0 @@
policy_module(docker, 1.0.0)
########################################
#
# Declarations
#
## <desc>
## <p>
## Allow sandbox containers manage fuse files
## </p>
## </desc>
gen_tunable(virt_sandbox_use_fusefs, false)
## <desc>
## <p>
## Determine whether docker can
## connect to all TCP ports.
## </p>
## </desc>
gen_tunable(docker_connect_any, false)
type docker_t;
type docker_exec_t;
init_daemon_domain(docker_t, docker_exec_t)
domain_subj_id_change_exemption(docker_t)
domain_role_change_exemption(docker_t)
type spc_t;
domain_type(spc_t)
role system_r types spc_t;
type spc_var_run_t;
files_pid_file(spc_var_run_t)
type docker_var_lib_t;
files_type(docker_var_lib_t)
type docker_home_t;
userdom_user_home_content(docker_home_t)
type docker_config_t;
files_config_file(docker_config_t)
type docker_lock_t;
files_lock_file(docker_lock_t)
type docker_log_t;
logging_log_file(docker_log_t)
type docker_tmp_t;
files_tmp_file(docker_tmp_t)
type docker_tmpfs_t;
files_tmpfs_file(docker_tmpfs_t)
type docker_var_run_t;
files_pid_file(docker_var_run_t)
type docker_unit_file_t;
systemd_unit_file(docker_unit_file_t)
type docker_devpts_t;
term_pty(docker_devpts_t)
type docker_share_t;
files_type(docker_share_t)
########################################
#
# docker local policy
#
allow docker_t self:capability { chown kill fowner fsetid mknod net_admin net_bind_service net_raw setfcap };
allow docker_t self:tun_socket relabelto;
allow docker_t self:process { getattr signal_perms setrlimit setfscreate };
allow docker_t self:fifo_file rw_fifo_file_perms;
allow docker_t self:unix_stream_socket create_stream_socket_perms;
allow docker_t self:tcp_socket create_stream_socket_perms;
allow docker_t self:udp_socket create_socket_perms;
allow docker_t self:capability2 block_suspend;
manage_files_pattern(docker_t, docker_home_t, docker_home_t)
manage_dirs_pattern(docker_t, docker_home_t, docker_home_t)
manage_lnk_files_pattern(docker_t, docker_home_t, docker_home_t)
userdom_admin_home_dir_filetrans(docker_t, docker_home_t, dir, ".docker")
manage_dirs_pattern(docker_t, docker_config_t, docker_config_t)
manage_files_pattern(docker_t, docker_config_t, docker_config_t)
files_etc_filetrans(docker_t, docker_config_t, dir, "docker")
manage_dirs_pattern(docker_t, docker_lock_t, docker_lock_t)
manage_files_pattern(docker_t, docker_lock_t, docker_lock_t)
files_lock_filetrans(docker_t, docker_lock_t, { dir file }, "lxc")
manage_dirs_pattern(docker_t, docker_log_t, docker_log_t)
manage_files_pattern(docker_t, docker_log_t, docker_log_t)
manage_lnk_files_pattern(docker_t, docker_log_t, docker_log_t)
logging_log_filetrans(docker_t, docker_log_t, { dir file lnk_file })
allow docker_t docker_log_t:dir_file_class_set { relabelfrom relabelto };
manage_dirs_pattern(docker_t, docker_tmp_t, docker_tmp_t)
manage_files_pattern(docker_t, docker_tmp_t, docker_tmp_t)
manage_lnk_files_pattern(docker_t, docker_tmp_t, docker_tmp_t)
files_tmp_filetrans(docker_t, docker_tmp_t, { dir file lnk_file })
manage_dirs_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_lnk_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_fifo_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_chr_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
manage_blk_files_pattern(docker_t, docker_tmpfs_t, docker_tmpfs_t)
allow docker_t docker_tmpfs_t:dir relabelfrom;
can_exec(docker_t, docker_tmpfs_t)
fs_tmpfs_filetrans(docker_t, docker_tmpfs_t, { dir file })
allow docker_t docker_tmpfs_t:chr_file mounton;
manage_dirs_pattern(docker_t, docker_share_t, docker_share_t)
manage_files_pattern(docker_t, docker_share_t, docker_share_t)
manage_lnk_files_pattern(docker_t, docker_share_t, docker_share_t)
allow docker_t docker_share_t:dir_file_class_set { relabelfrom relabelto };
can_exec(docker_t, docker_share_t)
#docker_filetrans_named_content(docker_t)
manage_dirs_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_chr_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_blk_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
manage_lnk_files_pattern(docker_t, docker_var_lib_t, docker_var_lib_t)
allow docker_t docker_var_lib_t:dir_file_class_set { relabelfrom relabelto };
files_var_lib_filetrans(docker_t, docker_var_lib_t, { dir file lnk_file })
manage_dirs_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_sock_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
manage_lnk_files_pattern(docker_t, docker_var_run_t, docker_var_run_t)
files_pid_filetrans(docker_t, docker_var_run_t, { dir file lnk_file sock_file })
allow docker_t docker_devpts_t:chr_file { relabelfrom rw_chr_file_perms setattr_chr_file_perms };
term_create_pty(docker_t, docker_devpts_t)
kernel_read_system_state(docker_t)
kernel_read_network_state(docker_t)
kernel_read_all_sysctls(docker_t)
kernel_rw_net_sysctls(docker_t)
kernel_setsched(docker_t)
kernel_read_all_proc(docker_t)
domain_use_interactive_fds(docker_t)
domain_dontaudit_read_all_domains_state(docker_t)
corecmd_exec_bin(docker_t)
corecmd_exec_shell(docker_t)
corenet_tcp_bind_generic_node(docker_t)
corenet_tcp_sendrecv_generic_if(docker_t)
corenet_tcp_sendrecv_generic_node(docker_t)
corenet_tcp_sendrecv_generic_port(docker_t)
corenet_tcp_bind_all_ports(docker_t)
corenet_tcp_connect_http_port(docker_t)
corenet_tcp_connect_commplex_main_port(docker_t)
corenet_udp_sendrecv_generic_if(docker_t)
corenet_udp_sendrecv_generic_node(docker_t)
corenet_udp_sendrecv_all_ports(docker_t)
corenet_udp_bind_generic_node(docker_t)
corenet_udp_bind_all_ports(docker_t)
files_read_config_files(docker_t)
files_dontaudit_getattr_all_dirs(docker_t)
files_dontaudit_getattr_all_files(docker_t)
fs_read_cgroup_files(docker_t)
fs_read_tmpfs_symlinks(docker_t)
fs_search_all(docker_t)
fs_getattr_all_fs(docker_t)
storage_raw_rw_fixed_disk(docker_t)
auth_use_nsswitch(docker_t)
auth_dontaudit_getattr_shadow(docker_t)
init_read_state(docker_t)
init_status(docker_t)
logging_send_audit_msgs(docker_t)
logging_send_syslog_msg(docker_t)
miscfiles_read_localization(docker_t)
mount_domtrans(docker_t)
seutil_read_default_contexts(docker_t)
seutil_read_config(docker_t)
sysnet_dns_name_resolve(docker_t)
sysnet_exec_ifconfig(docker_t)
optional_policy(`
rpm_exec(docker_t)
rpm_read_db(docker_t)
rpm_exec(docker_t)
')
optional_policy(`
fstools_domtrans(docker_t)
')
optional_policy(`
iptables_domtrans(docker_t)
')
optional_policy(`
openvswitch_stream_connect(docker_t)
')
#
# lxc rules
#
allow docker_t self:capability { dac_override setgid setpcap setuid sys_admin sys_boot sys_chroot sys_ptrace };
allow docker_t self:process { getcap setcap setexec setpgid setsched signal_perms };
allow docker_t self:netlink_route_socket rw_netlink_socket_perms;;
allow docker_t self:netlink_audit_socket create_netlink_socket_perms;
allow docker_t self:unix_dgram_socket { create_socket_perms sendto };
allow docker_t self:unix_stream_socket { create_stream_socket_perms connectto };
allow docker_t docker_var_lib_t:dir mounton;
allow docker_t docker_var_lib_t:chr_file mounton;
can_exec(docker_t, docker_var_lib_t)
kernel_dontaudit_setsched(docker_t)
kernel_get_sysvipc_info(docker_t)
kernel_request_load_module(docker_t)
kernel_mounton_messages(docker_t)
kernel_mounton_all_proc(docker_t)
kernel_mounton_all_sysctls(docker_t)
kernel_unlabeled_entry_type(spc_t)
kernel_unlabeled_domtrans(docker_t, spc_t)
dev_getattr_all(docker_t)
dev_getattr_sysfs_fs(docker_t)
dev_read_urand(docker_t)
dev_read_lvm_control(docker_t)
dev_rw_sysfs(docker_t)
dev_rw_loop_control(docker_t)
dev_rw_lvm_control(docker_t)
files_getattr_isid_type_dirs(docker_t)
files_manage_isid_type_dirs(docker_t)
files_manage_isid_type_files(docker_t)
files_manage_isid_type_symlinks(docker_t)
files_manage_isid_type_chr_files(docker_t)
files_manage_isid_type_blk_files(docker_t)
files_exec_isid_files(docker_t)
files_mounton_isid(docker_t)
files_mounton_non_security(docker_t)
files_mounton_isid_type_chr_file(docker_t)
fs_mount_all_fs(docker_t)
fs_unmount_all_fs(docker_t)
fs_remount_all_fs(docker_t)
files_mounton_isid(docker_t)
fs_manage_cgroup_dirs(docker_t)
fs_manage_cgroup_files(docker_t)
fs_relabelfrom_xattr_fs(docker_t)
fs_relabelfrom_tmpfs(docker_t)
fs_read_tmpfs_symlinks(docker_t)
fs_list_hugetlbfs(docker_t)
term_use_generic_ptys(docker_t)
term_use_ptmx(docker_t)
term_getattr_pty_fs(docker_t)
term_relabel_pty_fs(docker_t)
term_mounton_unallocated_ttys(docker_t)
modutils_domtrans_insmod(docker_t)
systemd_status_all_unit_files(docker_t)
systemd_start_systemd_services(docker_t)
userdom_stream_connect(docker_t)
userdom_search_user_home_content(docker_t)
userdom_read_all_users_state(docker_t)
userdom_relabel_user_home_files(docker_t)
userdom_relabel_user_tmp_files(docker_t)
userdom_relabel_user_tmp_dirs(docker_t)
optional_policy(`
gpm_getattr_gpmctl(docker_t)
')
optional_policy(`
dbus_system_bus_client(docker_t)
init_dbus_chat(docker_t)
init_start_transient_unit(docker_t)
optional_policy(`
systemd_dbus_chat_logind(docker_t)
')
optional_policy(`
firewalld_dbus_chat(docker_t)
')
')
optional_policy(`
udev_read_db(docker_t)
')
optional_policy(`
virt_read_config(docker_t)
virt_exec(docker_t)
virt_stream_connect(docker_t)
virt_stream_connect_sandbox(docker_t)
virt_exec_sandbox_files(docker_t)
virt_manage_sandbox_files(docker_t)
virt_relabel_sandbox_filesystem(docker_t)
# for lxc
virt_transition_svirt_sandbox(docker_t, system_r)
virt_mounton_sandbox_file(docker_t)
# virt_attach_sandbox_tun_iface(docker_t)
allow docker_t svirt_sandbox_domain:tun_socket relabelfrom;
')
tunable_policy(`docker_connect_any',`
corenet_tcp_connect_all_ports(docker_t)
corenet_sendrecv_all_packets(docker_t)
corenet_tcp_sendrecv_all_ports(docker_t)
')
########################################
#
# spc local policy
#
domain_entry_file(spc_t, docker_share_t)
domain_entry_file(spc_t, docker_var_lib_t)
role system_r types spc_t;
domain_entry_file(spc_t, docker_share_t)
domain_entry_file(spc_t, docker_var_lib_t)
domtrans_pattern(docker_t, docker_share_t, spc_t)
domtrans_pattern(docker_t, docker_var_lib_t, spc_t)
allow docker_t spc_t:process { setsched signal_perms };
ps_process_pattern(docker_t, spc_t)
allow docker_t spc_t:socket_class_set { relabelto relabelfrom };
optional_policy(`
dbus_chat_system_bus(spc_t)
')
optional_policy(`
unconfined_domain_noaudit(spc_t)
')
optional_policy(`
unconfined_domain(docker_t)
')
optional_policy(`
virt_transition_svirt_sandbox(spc_t, system_r)
')
########################################
#
# docker upstream policy
#
optional_policy(`
# domain_stub_named_filetrans_domain()
gen_require(`
attribute named_filetrans_domain;
')
docker_filetrans_named_content(named_filetrans_domain)
')
optional_policy(`
lvm_stub()
docker_rw_sem(lvm_t)
')
optional_policy(`
staff_stub()
docker_stream_connect(staff_t)
docker_exec(staff_t)
')
optional_policy(`
virt_stub_lxc()
docker_exec_lib(virtd_lxc_t)
')
optional_policy(`
virt_stub_svirt_sandbox_domain()
virt_stub_svirt_sandbox_file()
allow svirt_sandbox_domain self:netlink_kobject_uevent_socket create_socket_perms;
docker_read_share_files(svirt_sandbox_domain)
docker_lib_filetrans(svirt_sandbox_domain,svirt_sandbox_file_t, sock_file)
docker_use_ptys(svirt_sandbox_domain)
docker_spc_stream_connect(svirt_sandbox_domain)
fs_list_tmpfs(svirt_sandbox_domain)
fs_rw_hugetlbfs_files(svirt_sandbox_domain)
fs_dontaudit_remount_tmpfs(svirt_sandbox_domain)
dev_dontaudit_mounton_sysfs(svirt_sandbox_domain)
tunable_policy(`virt_sandbox_use_fusefs',`
fs_manage_fusefs_dirs(svirt_sandbox_domain)
fs_manage_fusefs_files(svirt_sandbox_domain)
fs_manage_fusefs_symlinks(svirt_sandbox_domain)
')
gen_require(`
attribute domain;
')
dontaudit svirt_sandbox_domain domain:key {search link};
')
Binary file not shown.
Regular → Executable
+24 -9
View File
@@ -1,19 +1,34 @@
#!/sbin/openrc-run
#!/sbin/runscript
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
command="${DOCKER_BINARY:-/usr/bin/docker}"
pidfile="${DOCKER_PIDFILE:-/run/${RC_SVCNAME}.pid}"
command_args="daemon -p \"${pidfile}\" ${DOCKER_OPTS}"
DOCKER_LOGFILE="${DOCKER_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
start_stop_daemon_args="--background \
--stderr \"${DOCKER_LOGFILE}\" --stdout \"${DOCKER_LOGFILE}\""
DOCKER_LOGFILE=${DOCKER_LOGFILE:-/var/log/${SVCNAME}.log}
DOCKER_PIDFILE=${DOCKER_PIDFILE:-/run/${SVCNAME}.pid}
DOCKER_BINARY=${DOCKER_BINARY:-/usr/bin/docker}
DOCKER_OPTS=${DOCKER_OPTS:-}
start_pre() {
start() {
checkpath -f -m 0644 -o root:docker "$DOCKER_LOGFILE"
ulimit -n 1048576
ulimit -u 1048576
return 0
ebegin "Starting docker daemon"
start-stop-daemon --start --background \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE" \
--stdout "$DOCKER_LOGFILE" \
--stderr "$DOCKER_LOGFILE" \
-- daemon -p "$DOCKER_PIDFILE" \
$DOCKER_OPTS
eend $?
}
stop() {
ebegin "Stopping docker daemon"
start-stop-daemon --stop \
--exec "$DOCKER_BINARY" \
--pidfile "$DOCKER_PIDFILE"
eend $?
}
-1
View File
@@ -5,7 +5,6 @@ After=network.target docker.socket
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/docker daemon -H fd://
MountFlags=slave
LimitNOFILE=1048576
+1 -14
View File
@@ -41,14 +41,7 @@ prestart() {
}
start() {
if [ ! -x $exec ]; then
if [ ! -e $exec ]; then
echo "Docker executable $exec not found"
else
echo "You do not have permission to execute the Docker executable $exec"
fi
exit 5
fi
[ -x $exec ] || exit 5
check_for_cleanup
@@ -65,13 +58,7 @@ start() {
while [ ! -f $pidfile -a $tries -lt 10 ]; do
sleep 1
tries=$((tries + 1))
echo -n '.'
done
if [ ! -f $pidfile ]; then
failure
echo
exit 1
fi
success
echo
else
+1 -1
View File
@@ -31,7 +31,7 @@
*
* This sample list was compiled as a combination of all the syscalls
* available on i386 and amd64 on Ubuntu Precise, as such it may not contain
* everything and not everything may be relevant for your system. This
* everything and not everything may be relevent for your system. This
* shouldn't be a problem.
*/
+1 -2
View File
@@ -8,5 +8,4 @@ targets_from() {
git ls-tree -r --name-only origin/master contrib/builder/deb | grep '/Dockerfile$' | sed -r 's!^contrib/builder/deb/|-debootstrap|/Dockerfile$!!g'
}
release_branch=$(git ls-remote --heads https://github.com/docker/docker.git | awk -F 'refs/heads/' '$2 ~ /^release/ { print $2 }' | sort -V | tail -1)
{ targets_from master; targets_from "$release_branch"; } | sort -u
{ targets_from master; targets_from release; } | sort -u
+1 -1
View File
@@ -31,7 +31,7 @@ stop on runlevel [!2345]
respawn
script
/usr/bin/docker daemon -H=tcp://0.0.0.0:2375
/usr/bin/docker -d -H=tcp://0.0.0.0:2375
end script
```

Some files were not shown because too many files have changed in this diff Show More