Merge pull request #29094 from vieux/1.13.0-rc3-cherrypicks

1.13.0-rc3 cherry-picks: part3
This commit is contained in:
Victor Vieux 2016-12-05 02:29:24 -08:00 committed by GitHub
commit 3ac2991ff8
39 changed files with 782 additions and 293 deletions

View file

@ -2,7 +2,7 @@
# -----------------------------------------------------------------------------------------
# This file describes the standard way to build Docker in a container on Windows
# Server 2016.
# Server 2016 or Windows 10.
#
# Maintainer: @jhowardmsft
# -----------------------------------------------------------------------------------------
@ -11,21 +11,25 @@
# Prerequisites:
# --------------
#
# 1. Windows Server 2016 with all Windows updates applied. Pre-release versions
# of Windows are not supported (eg Windows Server 2016 TP5). The build number
# must be at least 14393. This can be confirmed, for example, by running the
# following from an elevated PowerShell prompt - this sample output is from a
# fully up to date machine as at late October 2016:
# 1. Windows Server 2016 or Windows 10 with all Windows updates applied. The major
# build number must be at least 14393. This can be confirmed, for example, by
# running the following from an elevated PowerShell prompt - this sample output
# is from a fully up to date machine as at mid-November 2016:
#
# >> PS C:\> $(gin).WindowsBuildLabEx
# >> 14393.321.amd64fre.rs1_release_inmarket.161004-2338
# >> 14393.447.amd64fre.rs1_release_inmarket.161102-0100
#
# 2. Git for Windows (or another git client) must be installed. https://git-scm.com/download/win.
#
# 3. The machine must be configured to run containers. For example, by following
# the quick start guidance at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start or
# https://github.com/docker/labs/blob/master/windows/windows-containers/Setup.md
#
# 4. If building in a Hyper-V VM: For Windows Server 2016 using Windows Server
# containers as the default option, it is recommended you have at least 1GB
# of memory assigned; For Windows 10 where Hyper-V Containers are employed, you
# should have at least 4GB of memory assigned. Note also, to run Hyper-V
# containers in a VM, it is necessary to configure the VM for nested virtualization.
# -----------------------------------------------------------------------------------------
@ -63,18 +67,16 @@
# >> docker build -t nativebuildimage -f Dockerfile.windows .
#
#
# 4. Build the docker executable binaries in a container:
# 4. Build the docker executable binaries:
#
# >> docker run --name binaries nativebuildimage sh -c 'cd /c/go/src/github.com/docker/docker; hack/make.sh binary'
# >> docker run --name binaries nativebuildimage hack\make.ps1 -Binary
#
#
# 5. Copy the binaries out of the above container, replacing HostPath with an appropriate destination
# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination
# folder on the host system where you want the binaries to be located.
#
# >> $v=$(Get-Content ".\VERSION" -raw).ToString().Replace("`n","").Trim()
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-client\docker-$v.exe C:\HostPath\docker.exe
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-daemon\dockerd.exe C:\HostPath\dockerd.exe
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-daemon\docker-proxy-$v.exe C:\HostPath\docker-proxy.exe
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\docker.exe C:\HostPath\docker.exe
# >> docker cp binaries:C:\go\src\github.com\docker\docker\bundles\dockerd.exe C:\HostPath\dockerd.exe
#
#
# 6. (Optional) Remove the interim container holding the built executable binaries:
@ -88,6 +90,39 @@
# image which has all the components required to build the binaries already installed.
#
# >> docker rmi nativebuildimage
#
# -----------------------------------------------------------------------------------------
# The validation tests can either run in a container, or directly on the host. To run in a
# container, ensure you have created the nativebuildimage above. Then run the following
# from an (elevated) Windows PowerShell prompt:
#
# >> docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat
# To run the validation tests on the host, from the root of the repository, run the
# following from a Windows PowerShell prompt (elevation is not required): (Note Go
# must be installed to run these tests)
#
# >> hack\make.ps1 -DCO -PkgImports -GoFormat
# -----------------------------------------------------------------------------------------
# To run unit tests, ensure you have created the nativebuildimage above. Then run the
# following from an (elevated) Windows PowerShell prompt:
#
# >> docker run --rm nativebuildimage hack\make.ps1 -TestUnit
# -----------------------------------------------------------------------------------------
# To run all tests and binary build, ensure you have created the nativebuildimage above. Then
# run the following from an (elevated) Windows PowerShell prompt:
#
# >> docker run nativebuildimage hack\make.ps1 -All
# -----------------------------------------------------------------------------------------
@ -96,28 +131,26 @@
# Important notes:
# ---------------
#
# The posix utilities from git aren't usable interactively as at October 2016. This
# is because they require a console window which isn't present in a container in Windows.
# See the example at the top of this file. Do NOT use -it in that docker run. It will not work.
# Don't attempt to use a bind-mount to pass a local directory as the bundles target
# directory. It does not work (golang attempts for follow a mapped folder incorrectly).
# Instead, use docker cp as per the example.
#
# Don't attempt to use a volume for passing the source through to the container. The posix utilities will
# balk at reparse points.
# go.zip is not removed from the image as it is used by the Windows CI servers
# to ensure the host and image are running consistent versions of go.
#
# The downloaded files are not cleared from the image. go.zip is used by the Windows
# CI servers to ensure the host and image are running consistent versions of go.
# Nanoserver support is a work in progress. Although the image will build if the
# FROM statement is updated, it will not work when running autogen through hack\make.ps1.
# It is suspected that the required GCC utilities (eg gcc, windres, windmc) silently
# quit due to the use of console hooks which are not available.
#
# The GIT installer isn't very good at unattended install. We use techniques described
# at the links below to force it to set the path and other options accordingly.
# >> http://superuser.com/questions/944576/git-for-windows-silent-install-silent-arguments
# and follow through to installer at
# >> https://github.com/ferventcoder/chocolatey-packages/blob/master/automatic/git.install/tools/chocolateyInstall.ps1
# The docker integration tests do not currently run in a container on Windows, predominantly
# due to Windows not supporting privileged mode, so anything using a volume would fail.
# They (along with the rest of the docker CI suite) can be run using
# https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/Invoke-DockerCI.ps1.
#
# As of October 2016, this does not work on Windows 10 client, just Windows Server 2016,
# and only with the default isolation mode (process). It does not work with isolation mode
# set to Hyper-V containers (hyperv).
# -----------------------------------------------------------------------------------------
# The number of build steps below are explicitly minimised to improve performance.
FROM microsoft/windowsservercore
@ -128,55 +161,102 @@ SHELL ["powershell", "-command"]
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
# - FROM_DOCKERFILE is used for detection of building within a container.
ENV GO_VERSION=1.7.3 `
GIT_LOCATION=https://github.com/git-for-windows/git/releases/download/v2.10.1.windows.1/Git-2.10.1-64-bit.exe `
GIT_VERSION=2.10.2 `
GOPATH=C:\go `
FROM_DOCKERFILE=1
WORKDIR C:\
RUN `
setx /M Path $($Env:PATH+';C:\gcc\bin;C:\go\bin'); `
`
$ErrorActionPreference = 'Stop'; `
$ProgressPreference = 'SilentlyContinue'; `
`
Function Test-Nano() { `
$EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId; `
return (($EditionId -eq 'ServerStandardNano') -or ($EditionId -eq 'ServerDataCenterNano') -or ($EditionId -eq 'NanoServer')); `
}`
`
Function Download-File([string] $source, [string] $target) { `
$wc = New-Object net.webclient; $wc.Downloadfile($source, $target) `
if (Test-Nano) { `
$handler = New-Object System.Net.Http.HttpClientHandler; `
$client = New-Object System.Net.Http.HttpClient($handler); `
$client.Timeout = New-Object System.TimeSpan(0, 30, 0); `
$cancelTokenSource = [System.Threading.CancellationTokenSource]::new(); `
$responseMsg = $client.GetAsync([System.Uri]::new($source), $cancelTokenSource.Token); `
$responseMsg.Wait(); `
if (!$responseMsg.IsCanceled) { `
$response = $responseMsg.Result; `
if ($response.IsSuccessStatusCode) { `
$downloadedFileStream = [System.IO.FileStream]::new($target, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write); `
$copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream); `
$copyStreamOp.Wait(); `
$downloadedFileStream.Close(); `
if ($copyStreamOp.Exception -ne $null) { throw $copyStreamOp.Exception } `
} `
} else { `
Throw ("Failed to download " + $source) `
}`
} else { `
$webClient = New-Object System.Net.WebClient; `
$webClient.DownloadFile($source, $target); `
} `
} `
`
setx /M PATH $('C:\git\bin;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); `
`
Write-Host INFO: Downloading git...; `
Download-File $Env:GIT_LOCATION gitsetup.exe; `
$location='https://github.com/git-for-windows/git/releases/download/v'+$env:GIT_VERSION+'.windows.1/PortableGit-'+$env:GIT_VERSION+'-64-bit.7z.exe'; `
Download-File $location C:\gitsetup.7z.exe; `
`
Write-Host INFO: Downloading go...; `
Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') go.zip; `
Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; `
`
Write-Host INFO: Downloading compiler 1 of 3...; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip gcc.zip; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
`
Write-Host INFO: Downloading compiler 2 of 3...; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip runtime.zip; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip C:\runtime.zip; `
`
Write-Host INFO: Downloading compiler 3 of 3...; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip binutils.zip; `
Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip C:\binutils.zip; `
`
Write-Host INFO: Installing git...; `
$installPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'; `
$installItem = 'Git_is1'; `
New-Item -Path $installPath -Name $installItem -Force; `
$installKey = $installPath+'\'+$installItem; `
New-ItemProperty $installKey -Name 'Inno Setup CodeFile: Path Option' -Value 'CmdTools' -PropertyType 'String' -Force; `
New-ItemProperty $installKey -Name 'Inno Setup CodeFile: Bash Terminal Option' -Value 'ConHost' -PropertyType 'String' -Force; `
New-ItemProperty $installKey -Name 'Inno Setup CodeFile: CRLF Option' -Value 'CRLFCommitAsIs' -PropertyType 'String' -Force; `
Start-Process gitsetup.exe -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /CLOSEAPPLICATIONS /DIR=C:\git\' -Wait; `
Write-Host INFO: Installing PS7Zip package...; `
Install-Package PS7Zip -Force | Out-Null; `
Write-Host INFO: Importing PS7Zip...; `
Import-Module PS7Zip -Force; `
New-Item C:\git -ItemType Directory | Out-Null ; `
cd C:\git; `
Write-Host INFO: Extracting git...; `
Expand-7Zip C:\gitsetup.7z.exe | Out-Null; `
cd C:\; `
`
Write-Host INFO: Expanding go...; `
Expand-Archive C:\go.zip -DestinationPath C:\; `
`
Write-Host INFO: Expanding compiler...; `
Write-Host INFO: Expanding compiler 1 of 3...; `
Expand-Archive C:\gcc.zip -DestinationPath C:\gcc -Force; `
Write-Host INFO: Expanding compiler 2 of 3...; `
Expand-Archive C:\runtime.zip -DestinationPath C:\gcc -Force; `
Write-Host INFO: Expanding compiler 3 of 3...; `
Expand-Archive C:\binutils.zip -DestinationPath C:\gcc -Force; `
`
Write-Host INFO: Removing downloaded files...; `
Remove-Item C:\gcc.zip; `
Remove-Item C:\runtime.zip; `
Remove-Item C:\binutils.zip; `
Remove-Item C:\gitsetup.7z.exe; `
`
Write-Host INFO: Creating source directory...; `
New-Item -ItemType Directory -Path C:\go\src\github.com\docker\docker | Out-Null; `
`
Write-Host INFO: Configuring git core.autocrlf...; `
C:\git\bin\git config --global core.autocrlf true; `
`
Write-Host INFO: Completed
# Prepare for building
COPY . C:\go\src\github.com\docker\docker
# Make PowerShell the default entrypoint
ENTRYPOINT ["powershell.exe"]
# Set the working directory to the location of the sources
WORKDIR C:\go\src\github.com\docker\docker
# Copy the sources into the container
COPY . .

View file

@ -32,17 +32,17 @@ type copyBackend interface {
// stateBackend includes functions to implement to provide container state lifecycle functionality.
type stateBackend interface {
ContainerCreate(config types.ContainerCreateConfig, validateHostname bool) (container.ContainerCreateCreatedBody, error)
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
ContainerKill(name string, sig uint64) error
ContainerPause(name string) error
ContainerRename(oldName, newName string) error
ContainerResize(name string, height, width int) error
ContainerRestart(name string, seconds *int) error
ContainerRm(name string, config *types.ContainerRmConfig) error
ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStop(name string, seconds *int) error
ContainerUnpause(name string) error
ContainerUpdate(name string, hostConfig *container.HostConfig, validateHostname bool) (container.ContainerUpdateOKBody, error)
ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error)
ContainerWait(name string, timeout time.Duration) (int, error)
}

View file

@ -156,8 +156,7 @@ func (s *containerRouter) postContainersStart(ctx context.Context, w http.Respon
checkpoint := r.Form.Get("checkpoint")
checkpointDir := r.Form.Get("checkpoint-dir")
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
if err := s.backend.ContainerStart(vars["name"], hostConfig, validateHostname, checkpoint, checkpointDir); err != nil {
if err := s.backend.ContainerStart(vars["name"], hostConfig, checkpoint, checkpointDir); err != nil {
return err
}
@ -332,7 +331,6 @@ func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.Respon
return err
}
version := httputils.VersionFromContext(ctx)
var updateConfig container.UpdateConfig
decoder := json.NewDecoder(r.Body)
@ -346,8 +344,7 @@ func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.Respon
}
name := vars["name"]
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
resp, err := s.backend.ContainerUpdate(name, hostConfig, validateHostname)
resp, err := s.backend.ContainerUpdate(name, hostConfig)
if err != nil {
return err
}
@ -372,14 +369,13 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo
version := httputils.VersionFromContext(ctx)
adjustCPUShares := versions.LessThan(version, "1.19")
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
ccr, err := s.backend.ContainerCreate(types.ContainerCreateConfig{
Name: name,
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
AdjustCPUShares: adjustCPUShares,
}, validateHostname)
})
if err != nil {
return err
}

View file

@ -116,7 +116,7 @@ type Backend interface {
// ContainerAttachRaw attaches to container.
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool) error
// ContainerCreate creates a new Docker container and returns potential warnings
ContainerCreate(config types.ContainerCreateConfig, validateHostname bool) (container.ContainerCreateCreatedBody, error)
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
// ContainerRm removes a container specified by `id`.
ContainerRm(name string, config *types.ContainerRmConfig) error
// Commit creates a new Docker image from an existing Docker container.
@ -124,7 +124,7 @@ type Backend interface {
// ContainerKill stops the container execution abruptly.
ContainerKill(containerID string, sig uint64) error
// ContainerStart starts a new container
ContainerStart(containerID string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
ContainerStart(containerID string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
// ContainerWait stops processing until the given container is stopped.
ContainerWait(containerID string, timeout time.Duration) (int, error)
// ContainerUpdateCmdOnBuild updates container.Path and container.Args

View file

@ -307,7 +307,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
return nil
}
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig}, true)
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig})
if err != nil {
return err
}

View file

@ -180,7 +180,7 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
return nil
}
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig}, true)
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig})
if err != nil {
return err
}
@ -496,7 +496,7 @@ func (b *Builder) create() (string, error) {
c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
Config: b.runConfig,
HostConfig: hostConfig,
}, true)
})
if err != nil {
return "", err
}
@ -537,7 +537,7 @@ func (b *Builder) run(cID string) (err error) {
}
}()
if err := b.docker.ContainerStart(cID, nil, true, "", ""); err != nil {
if err := b.docker.ContainerStart(cID, nil, "", ""); err != nil {
close(finished)
if cancelErr := <-cancelErrCh; cancelErr != nil {
logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v",

View file

@ -176,17 +176,10 @@ func Parse(rwc io.Reader, d *Directive) (*Node, error) {
newline := scanner.Text()
currentLine++
// If escape followed by a comment line then stop
// Note here that comment line starts with `#` at
// the first pos of the line
if stripComments(newline) == "" {
break
if stripComments(strings.TrimSpace(newline)) == "" {
continue
}
// If escape followed by an empty line then stop
if strings.TrimSpace(newline) == "" {
break
}
line, child, err = ParseLine(line+newline, d, false)
if err != nil {
return nil, err

View file

@ -150,8 +150,8 @@ func TestLineInformation(t *testing.T) {
t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err)
}
if ast.StartLine != 5 || ast.EndLine != 27 {
fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 27, ast.StartLine, ast.EndLine)
if ast.StartLine != 5 || ast.EndLine != 31 {
fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 31, ast.StartLine, ast.EndLine)
t.Fatalf("Root line information doesn't match result.")
}
if len(ast.Children) != 3 {
@ -161,7 +161,7 @@ func TestLineInformation(t *testing.T) {
expected := [][]int{
{5, 5},
{11, 12},
{17, 27},
{17, 31},
}
for i, child := range ast.Children {
if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] {

View file

@ -16,11 +16,15 @@ ENV GOPATH \
# Install the packages we need, clean up after them and us
RUN apt-get update \
&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean \
&& apt-get install -y --no-install-recommends git golang ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists \
&& go get -v github.com/brimstone/consuldock \
&& mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \
&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
&& rm /tmp/dpkg.* \

View file

@ -16,8 +16,10 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends git golang ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists \
&& go get -v github.com/brimstone/consuldock \
&& mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \
&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
&& rm /tmp/dpkg.* \

View file

@ -23,12 +23,14 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends unzip wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists \
&& cd /tmp \
&& wget https://dl.bintray.com/mitchellh/consul/0.3.1_web_ui.zip \
-O web_ui.zip \
&& unzip web_ui.zip \
&& mv dist /webui \
&& rm web_ui.zip \
&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
&& rm /tmp/dpkg.*
@ -40,8 +42,10 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends git golang ca-certificates build-essential \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists \
&& go get -v github.com/hashicorp/consul \
&& mv $GOPATH/bin/consul /usr/bin/consul \
&& dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
&& apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
&& rm /tmp/dpkg.* \

View file

@ -27,5 +27,8 @@ bye\
frog
RUN echo hello \
# this is a comment that breaks escape continuation
RUN echo this is some more useful stuff
# this is a comment
# this is a comment with a blank line surrounding it
this is some more useful stuff

View file

@ -6,5 +6,4 @@
(run "echo hi world goodnight")
(run "echo goodbyefrog")
(run "echo goodbyefrog")
(run "echo hello")
(run "echo this is some more useful stuff")
(run "echo hello this is some more useful stuff")

View file

@ -1,15 +0,0 @@
FROM busybox
# The following will create two instructions
# `Run foo`
# `bar`
# because empty line will break the escape.
# The parser will generate the following:
# (from "busybox")
# (run "foo")
# (bar "")
# And `bar` will return an error instruction later
# Note: Parse() will not immediately error out.
RUN foo \
bar

View file

@ -1,3 +0,0 @@
(from "busybox")
(run "foo")
(bar "")

View file

@ -6,7 +6,9 @@ RUN apt-get \update && \
ADD \conf\\" /.znc
RUN foo \
bar \
baz
CMD [ "\/usr\\\"/bin/znc", "-f", "-r" ]

View file

@ -7,6 +7,7 @@ import (
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/stringutils"
"github.com/spf13/cobra"
"golang.org/x/net/context"
@ -43,17 +44,19 @@ func runList(dockerCli *command.DockerCli, opts listOptions) error {
}
w := tabwriter.NewWriter(dockerCli.Out(), 20, 1, 3, ' ', 0)
fmt.Fprintf(w, "NAME \tTAG \tDESCRIPTION\tENABLED")
fmt.Fprintf(w, "ID \tNAME \tTAG \tDESCRIPTION\tENABLED")
fmt.Fprintf(w, "\n")
for _, p := range plugins {
id := p.ID
desc := strings.Replace(p.Config.Description, "\n", " ", -1)
desc = strings.Replace(desc, "\r", " ", -1)
if !opts.noTrunc {
id = stringid.TruncateID(p.ID)
desc = stringutils.Ellipsis(desc, 45)
}
fmt.Fprintf(w, "%s\t%s\t%s\t%v\n", p.Name, p.Tag, desc, p.Enabled)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%v\n", id, p.Name, p.Tag, desc, p.Enabled)
}
w.Flush()
return nil

View file

@ -45,7 +45,7 @@ func NewInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
var elementSearcher inspect.GetRefFunc
switch opts.inspectType {
case "", "container", "image", "node", "network", "service", "volume", "task":
case "", "container", "image", "node", "network", "service", "volume", "task", "plugin":
elementSearcher = inspectAll(context.Background(), dockerCli, opts.size, opts.inspectType)
default:
return fmt.Errorf("%q is not a valid value for --type", opts.inspectType)
@ -95,6 +95,12 @@ func inspectVolume(ctx context.Context, dockerCli *command.DockerCli) inspect.Ge
}
}
func inspectPlugin(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
return func(ref string) (interface{}, []byte, error) {
return dockerCli.Client().PluginInspectWithRaw(ctx, ref)
}
}
func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool, typeConstraint string) inspect.GetRefFunc {
var inspectAutodetect = []struct {
ObjectType string
@ -108,6 +114,7 @@ func inspectAll(ctx context.Context, dockerCli *command.DockerCli, getSize bool,
{"service", false, inspectService(ctx, dockerCli)},
{"task", false, inspectTasks(ctx, dockerCli)},
{"node", false, inspectNode(ctx, dockerCli)},
{"plugin", false, inspectPlugin(ctx, dockerCli)},
}
isErrNotSwarmManager := func(err error) bool {

View file

@ -255,3 +255,24 @@ func IsErrSecretNotFound(err error) bool {
_, ok := err.(secretNotFoundError)
return ok
}
// pluginNotFoundError implements an error returned when a plugin is not in the docker host.
type pluginNotFoundError struct {
name string
}
// NotFound indicates that this error type is of NotFound
func (e pluginNotFoundError) NotFound() bool {
return true
}
// Error returns a string representation of a pluginNotFoundError
func (e pluginNotFoundError) Error() string {
return fmt.Sprintf("Error: No such plugin: %s", e.name)
}
// IsErrPluginNotFound returns true if the error is caused
// when a plugin is not found in the docker host.
func IsErrPluginNotFound(err error) bool {
return IsErrNotFound(err)
}

View file

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/docker/docker/api/types"
"golang.org/x/net/context"
@ -13,6 +14,9 @@ import (
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
resp, err := cli.get(ctx, "/plugins/"+name, nil, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
return nil, nil, pluginNotFoundError{name}
}
return nil, nil, err
}

View file

@ -28,8 +28,8 @@ type Backend interface {
FindNetwork(idName string) (libnetwork.Network, error)
SetupIngress(req clustertypes.NetworkCreateRequest, nodeIP string) error
PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
CreateManagedContainer(config types.ContainerCreateConfig, validateHostname bool) (container.ContainerCreateCreatedBody, error)
ContainerStart(name string, hostConfig *container.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
ContainerStop(name string, seconds *int) error
ContainerLogs(context.Context, string, *backend.ContainerLogsConfig, chan struct{}) error
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error

View file

@ -11,12 +11,10 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/digest"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/daemon/cluster/convert"
executorpkg "github.com/docker/docker/daemon/cluster/executor"
"github.com/docker/docker/reference"
@ -215,8 +213,6 @@ func (c *containerAdapter) waitForDetach(ctx context.Context) error {
func (c *containerAdapter) create(ctx context.Context) error {
var cr containertypes.ContainerCreateCreatedBody
var err error
version := httputils.VersionFromContext(ctx)
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
if cr, err = c.backend.CreateManagedContainer(types.ContainerCreateConfig{
Name: c.container.name(),
@ -224,7 +220,7 @@ func (c *containerAdapter) create(ctx context.Context) error {
HostConfig: c.container.hostConfig(),
// Use the first network in container create
NetworkingConfig: c.container.createNetworkingConfig(),
}, validateHostname); err != nil {
}); err != nil {
return err
}
@ -263,9 +259,7 @@ func (c *containerAdapter) create(ctx context.Context) error {
}
func (c *containerAdapter) start(ctx context.Context) error {
version := httputils.VersionFromContext(ctx)
validateHostname := versions.GreaterThanOrEqualTo(version, "1.24")
return c.backend.ContainerStart(c.container.name(), nil, validateHostname, "", "")
return c.backend.ContainerStart(c.container.name(), nil, "", "")
}
func (c *containerAdapter) inspect(ctx context.Context) (types.ContainerJSON, error) {

View file

@ -3,7 +3,6 @@ package daemon
import (
"fmt"
"path/filepath"
"regexp"
"time"
"github.com/docker/docker/api/errors"
@ -204,7 +203,7 @@ func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *
// verifyContainerSettings performs validation of the hostconfig and config
// structures.
func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool, validateHostname bool) ([]string, error) {
func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
// First perform verification of settings common across all platforms.
if config != nil {
@ -222,18 +221,6 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon
}
}
// Validate if the given hostname is RFC 1123 (https://tools.ietf.org/html/rfc1123) compliant.
if validateHostname && len(config.Hostname) > 0 {
// RFC1123 specifies that 63 bytes is the maximium length
// Windows has the limitation of 63 bytes in length
// Linux hostname is limited to HOST_NAME_MAX=64, not including the terminating null byte.
// We limit the length to 63 bytes here to match RFC1035 and RFC1123.
matched, _ := regexp.MatchString("^(([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])\\.)*([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])$", config.Hostname)
if len(config.Hostname) > 63 || !matched {
return nil, fmt.Errorf("invalid hostname format: %s", config.Hostname)
}
}
// Validate if Env contains empty variable or not (e.g., ``, `=foo`)
for _, env := range config.Env {
if _, err := opts.ValidateEnv(env); err != nil {

View file

@ -25,22 +25,22 @@ import (
)
// CreateManagedContainer creates a container that is managed by a Service
func (daemon *Daemon) CreateManagedContainer(params types.ContainerCreateConfig, validateHostname bool) (containertypes.ContainerCreateCreatedBody, error) {
return daemon.containerCreate(params, true, validateHostname)
func (daemon *Daemon) CreateManagedContainer(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
return daemon.containerCreate(params, true)
}
// ContainerCreate creates a regular container
func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig, validateHostname bool) (containertypes.ContainerCreateCreatedBody, error) {
return daemon.containerCreate(params, false, validateHostname)
func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (containertypes.ContainerCreateCreatedBody, error) {
return daemon.containerCreate(params, false)
}
func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool, validateHostname bool) (containertypes.ContainerCreateCreatedBody, error) {
func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool) (containertypes.ContainerCreateCreatedBody, error) {
start := time.Now()
if params.Config == nil {
return containertypes.ContainerCreateCreatedBody{}, fmt.Errorf("Config cannot be empty in order to create a container")
}
warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false, validateHostname)
warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false)
if err != nil {
return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, err
}

View file

@ -19,7 +19,7 @@ import (
)
// ContainerStart starts a container.
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error {
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error {
if checkpoint != "" && !daemon.HasExperimental() {
return apierrors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode"))
}
@ -73,7 +73,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
// check if hostConfig is in line with the current system settings.
// It may happen cgroups are umounted or the like.
if _, err = daemon.verifyContainerSettings(container.HostConfig, nil, false, validateHostname); err != nil {
if _, err = daemon.verifyContainerSettings(container.HostConfig, nil, false); err != nil {
return err
}
// Adapt for old containers in case we have updates in this function and

View file

@ -7,10 +7,10 @@ import (
)
// ContainerUpdate updates configuration of the container
func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig, validateHostname bool) (container.ContainerUpdateOKBody, error) {
func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) (container.ContainerUpdateOKBody, error) {
var warnings []string
warnings, err := daemon.verifyContainerSettings(hostConfig, nil, true, validateHostname)
warnings, err := daemon.verifyContainerSettings(hostConfig, nil, true)
if err != nil {
return container.ContainerUpdateOKBody{Warnings: warnings}, err
}

View file

@ -3962,8 +3962,9 @@ List nodes
**Status codes**:
- **200** no error
- **500** server error
- **200** no error
- **406** - node is not part of a swarm
- **500** server error
#### Inspect a node
@ -4045,6 +4046,7 @@ Return low-level information on the node `id`
- **200** no error
- **404** no such node
- **406** node is not part of a swarm
- **500** server error
#### Remove a node
@ -4073,6 +4075,7 @@ Remove a node from the swarm.
- **200** no error
- **404** no such node
- **406** node is not part of a swarm
- **500** server error
#### Update a node
@ -4128,6 +4131,7 @@ JSON Parameters:
- **200** no error
- **404** no such node
- **406** node is not part of a swarm
- **500** server error
### 3.8 Swarm
@ -4178,7 +4182,9 @@ Inspect swarm
**Status codes**:
- **200** - no error
- **200** - no error
- **406** node is not part of a swarm
- **500** - sever error
#### Initialize a new swarm
@ -4216,9 +4222,10 @@ Initialize a new swarm. The body of the HTTP response includes the node ID.
**Status codes**:
- **200** no error
- **400** bad parameter
- **406** node is already part of a swarm
- **200** no error
- **400** bad parameter
- **406** node is already part of a swarm
- **500** - server error
JSON Parameters:
@ -4282,9 +4289,10 @@ Join an existing swarm
**Status codes**:
- **200** no error
- **400** bad parameter
- **406** node is already part of a swarm
- **200** no error
- **400** bad parameter
- **406** node is already part of a swarm
- **500** - server error
JSON Parameters:
@ -4321,8 +4329,9 @@ Leave a swarm
**Status codes**:
- **200** no error
- **406** node is not part of a swarm
- **200** no error
- **406** node is not part of a swarm
- **500** - server error
#### Update a swarm
@ -4374,9 +4383,10 @@ Update a swarm
**Status codes**:
- **200** no error
- **400** bad parameter
- **406** node is not part of a swarm
- **200** no error
- **400** bad parameter
- **406** node is not part of a swarm
- **500** - server error
JSON Parameters:
@ -4511,8 +4521,9 @@ List services
**Status codes**:
- **200** no error
- **500** server error
- **200** no error
- **406** node is not part of a swarm
- **500** server error
#### Create a service
@ -4606,9 +4617,10 @@ image](#create-an-image) section for more details.
**Status codes**:
- **201** no error
- **406** server error or node is not part of a swarm
- **409** name conflicts with an existing object
- **201** no error
- **406** node is not part of a swarm
- **409** name conflicts with an existing object
- **500** - server error
**JSON Parameters**:
@ -4708,6 +4720,7 @@ Stop and remove the service `id`
- **200** no error
- **404** no such service
- **406** - node is not part of a swarm
- **500** server error
#### Inspect one or more services
@ -4797,6 +4810,7 @@ Return information on the service `id`.
- **200** no error
- **404** no such service
- **406** - node is not part of a swarm
- **500** server error
#### Update a service
@ -4930,6 +4944,7 @@ image](#create-an-image) section for more details.
- **200** no error
- **404** no such service
- **406** - node is not part of a swarm
- **500** server error
### 3.10 Tasks
@ -5131,15 +5146,16 @@ List tasks
**Status codes**:
- **200** no error
- **500** server error
- **200** no error
- **406** - node is not part of a swarm
- **500** server error
#### Inspect a task
`GET /tasks/(task id)`
`GET /tasks/(id)`
Get details on a task
Get details on the task `id`
**Example request**:
@ -5233,9 +5249,10 @@ Get details on a task
**Status codes**:
- **200** no error
- **404** unknown task
- **500** server error
- **200** no error
- **404** unknown task
- **406** - node is not part of a swarm
- **500** server error
## 4. Going further

View file

@ -34,7 +34,7 @@ The `docker logs` command batch-retrieves logs present at the time of execution.
> **Note**: this command is only functional for containers that are started with
> the `json-file` or `journald` logging driver.
For more information about selecting and configuring login-drivers, refer to
For more information about selecting and configuring logging drivers, refer to
[Configure logging drivers](https://docs.docker.com/engine/admin/logging/overview/).
The `docker logs --follow` command will continue streaming the new output from

View file

@ -36,8 +36,8 @@ Example output:
```bash
$ docker plugin ls
NAME TAG DESCRIPTION ENABLED
tiborvass/no-remove latest A test plugin for Docker true
ID NAME TAG DESCRIPTION ENABLED
69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true
```
## Related information

View file

@ -35,7 +35,7 @@ The `docker service logs` command batch-retrieves logs present at the time of ex
> **Note**: this command is only functional for services that are started with
> the `json-file` or `journald` logging driver.
For more information about selecting and configuring login-drivers, refer to
For more information about selecting and configuring logging drivers, refer to
[Configure logging drivers](https://docs.docker.com/engine/admin/logging/overview/).
The `docker service logs --follow` command will continue streaming the new output from

401
hack/make.ps1 Normal file
View file

@ -0,0 +1,401 @@
<#
.NOTES
Author: @jhowardmsft
Summary: Windows native build script. This is similar to functionality provided
by hack\make.sh, but uses native Windows PowerShell semantics. It does
not support the full set of options provided by the Linux counterpart.
For example:
- You can't cross-build Linux docker binaries on Windows
- Hashes aren't generated on binaries
- 'Releasing' isn't supported.
- Integration tests. This is because they currently cannot run inside a container,
and require significant external setup.
It does however provided the minimum necessary to support parts of local Windows
development and Windows to Windows CI.
Usage Examples (run from repo root):
"hack\make.ps1 -Binary" to build the binaries
"hack\make.ps1 -Client" to build just the client 64-bit binary
"hack\make.ps1 -TestUnit" to run unit tests
"hack\make.ps1 -Binary -TestUnit" to build the binaries and run unit tests
"hack\make.ps1 -All" to run everything this script knows about
.PARAMETER Client
Builds the client binaries.
.PARAMETER Daemon
Builds the daemon binary.
.PARAMETER Binary
Builds the client binaries and the daemon binary. A convenient shortcut to `make.ps1 -Client -Daemon`.
.PARAMETER Race
Use -race in go build and go test.
.PARAMETER Noisy
Use -v in go build.
.PARAMETER ForceBuildAll
Use -a in go build.
.PARAMETER NoOpt
Use -gcflags -N -l in go build to disable optimisation (can aide debugging).
.PARAMETER CommitSuffix
Adds a custom string to be appended to the commit ID (spaces are stripped).
.PARAMETER DCO
Runs the DCO (Developer Certificate Of Origin) test.
.PARAMETER PkgImports
Runs the pkg\ directory imports test.
.PARAMETER GoFormat
Runs the Go formatting test.
.PARAMETER TestUnit
Runs unit tests.
.PARAMETER All
Runs everything this script knows about.
TODO
- Unify the head commit
- Sort out the GITCOMMIT environment variable in the absense of a .git (longer term)
- Add golint and other checks (swagger maybe?)
#>
param(
[Parameter(Mandatory=$False)][switch]$Client,
[Parameter(Mandatory=$False)][switch]$Daemon,
[Parameter(Mandatory=$False)][switch]$Binary,
[Parameter(Mandatory=$False)][switch]$Race,
[Parameter(Mandatory=$False)][switch]$Noisy,
[Parameter(Mandatory=$False)][switch]$ForceBuildAll,
[Parameter(Mandatory=$False)][switch]$NoOpt,
[Parameter(Mandatory=$False)][string]$CommitSuffix="",
[Parameter(Mandatory=$False)][switch]$DCO,
[Parameter(Mandatory=$False)][switch]$PkgImports,
[Parameter(Mandatory=$False)][switch]$GoFormat,
[Parameter(Mandatory=$False)][switch]$TestUnit,
[Parameter(Mandatory=$False)][switch]$All
)
$ErrorActionPreference = "Stop"
$pushed=$False # To restore the directory if we have temporarily pushed to one.
# Utility function to get the commit ID of the repository
Function Get-GitCommit() {
if (-not (Test-Path ".\.git")) {
# If we don't have a .git directory, but we do have the environment
# variable DOCKER_GITCOMMIT set, that can override it.
if ($env:DOCKER_GITCOMMIT.Length -eq 0) {
Throw ".git directory missing and DOCKER_GITCOMMIT environment variable not specified."
}
Write-Host "INFO: Git commit assumed from DOCKER_GITCOMMIT environment variable"
return $env:DOCKER_GITCOMMIT
}
$gitCommit=$(git rev-parse --short HEAD)
if ($(git status --porcelain --untracked-files=no).Length -ne 0) {
$gitCommit="$gitCommit-unsupported"
Write-Host ""
Write-Warning "This version is unsupported because there are uncommitted file(s)."
Write-Warning "Either commit these changes, or add them to .gitignore."
git status --porcelain --untracked-files=no | Write-Warning
Write-Host ""
}
return $gitCommit
}
# Utility function to get get the current build version of docker
Function Get-DockerVersion() {
if (-not (Test-Path ".\VERSION")) { Throw "VERSION file not found. Is this running from the root of a docker repository?" }
return $(Get-Content ".\VERSION" -raw).ToString().Replace("`n","").Trim()
}
# Utility function to determine if we are running in a container or not.
# In Windows, we get this through an environment variable set in `Dockerfile.Windows`
Function Check-InContainer() {
if ($env:FROM_DOCKERFILE.Length -eq 0) {
Write-Host ""
Write-Warning "Not running in a container. The result might be an incorrect build."
Write-Host ""
}
}
# Utility function to get the commit for HEAD
Function Get-HeadCommit() {
$head = Invoke-Expression "git rev-parse --verify HEAD"
if ($LASTEXITCODE -ne 0) { Throw "Failed getting HEAD commit" }
return $head
}
# Utility function to get the commit for upstream
Function Get-UpstreamCommit() {
Invoke-Expression "git fetch -q https://github.com/docker/docker.git refs/heads/master"
if ($LASTEXITCODE -ne 0) { Throw "Failed fetching" }
$upstream = Invoke-Expression "git rev-parse --verify FETCH_HEAD"
if ($LASTEXITCODE -ne 0) { Throw "Failed getting upstream commit" }
return $upstream
}
# Build a binary (client or daemon)
Function Execute-Build($type, $additionalBuildTags, $directory) {
# Generate the build flags
$buildTags = "autogen"
if ($Noisy) { $verboseParm=" -v" }
if ($Race) { Write-Warning "Using race detector"; $raceParm=" -race"}
if ($ForceBuildAll) { $allParm=" -a" }
if ($NoOpt) { $optParm=" -gcflags "+""""+"-N -l"+"""" }
if ($addtionalBuildTags -ne "") { $buildTags += $(" " + $additionalBuildTags) }
# Do the go build in the appropriate directory
# Note -linkmode=internal is required to be able to debug on Windows.
# https://github.com/golang/go/issues/14319#issuecomment-189576638
Write-Host "INFO: Building $type..."
Push-Location $root\cmd\$directory; $global:pushed=$True
$buildCommand = "go build" + `
$raceParm + `
$verboseParm + `
$allParm + `
$optParm + `
" -tags """ + $buildTags + """" + `
" -ldflags """ + "-linkmode=internal" + """" + `
" -o $root\bundles\"+$directory+".exe"
Invoke-Expression $buildCommand
if ($LASTEXITCODE -ne 0) { Throw "Failed to compile $type" }
Pop-Location; $global:pushed=$False
}
# Validates the DCO marker is present on each commit
Function Validate-DCO($headCommit, $upstreamCommit) {
Write-Host "INFO: Validating Developer Certificate of Origin..."
# Username may only contain alphanumeric characters or dashes and cannot begin with a dash
$usernameRegex='[a-zA-Z0-9][a-zA-Z0-9-]+'
$dcoPrefix="Signed-off-by:"
$dcoRegex="^(Docker-DCO-1.1-)?$dcoPrefix ([^<]+) <([^<>@]+@[^<>]+)>( \\(github: ($githubUsernameRegex)\\))?$"
$counts = Invoke-Expression "git diff --numstat $upstreamCommit...$headCommit"
if ($LASTEXITCODE -ne 0) { Throw "Failed git diff --numstat" }
# Counts of adds and deletes after removing multiple white spaces. AWK anyone? :(
$adds=0; $dels=0; $($counts -replace '\s+', ' ') | %{ $a=$_.Split(" "); $adds+=[int]$a[0]; $dels+=[int]$a[1] }
if (($adds -eq 0) -and ($dels -eq 0)) {
Write-Warning "DCO validation - nothing to validate!"
return
}
$commits = Invoke-Expression "git log $upstreamCommit..$headCommit --format=format:%H%n"
if ($LASTEXITCODE -ne 0) { Throw "Failed git log --format" }
$commits = $($commits -split '\s+' -match '\S')
$badCommits=@()
$commits | %{
# Skip commits with no content such as merge commits etc
if ($(git log -1 --format=format: --name-status $_).Length -gt 0) {
# Ignore exit code on next call - always process regardless
$commitMessage = Invoke-Expression "git log -1 --format=format:%B --name-status $_"
if (($commitMessage -match $dcoRegex).Length -eq 0) { $badCommits+=$_ }
}
}
if ($badCommits.Length -eq 0) {
Write-Host "Congratulations! All commits are properly signed with the DCO!"
} else {
$e = "`nThese commits do not have a proper '$dcoPrefix' marker:`n"
$badCommits | %{ $e+=" - $_`n"}
$e += "`nPlease amend each commit to include a properly formatted DCO marker.`n`n"
$e += "Visit the following URL for information about the Docker DCO:`n"
$e += "https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work`n"
Throw $e
}
}
# Validates that .\pkg\... is safely isolated from internal code
Function Validate-PkgImports($headCommit, $upstreamCommit) {
Write-Host "INFO: Validating pkg import isolation..."
# Get a list of go source-code files which have changed under pkg\. Ignore exit code on next call - always process regardless
$files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'pkg\*.go`'"
$badFiles=@(); $files | %{
$file=$_
# For the current changed file, get its list of dependencies, sorted and uniqued.
$imports = Invoke-Expression "go list -e -f `'{{ .Deps }}`' $file"
if ($LASTEXITCODE -ne 0) { Throw "Failed go list for dependencies on $file" }
$imports = $imports -Replace "\[" -Replace "\]", "" -Split(" ") | Sort-Object | Get-Unique
# Filter out what we are looking for
$imports = $imports -NotMatch "^github.com/docker/docker/pkg/" `
-NotMatch "^github.com/docker/docker/vendor" `
-Match "^github.com/docker/docker" `
-Replace "`n", ""
$imports | % { $badFiles+="$file imports $_`n" }
}
if ($badFiles.Length -eq 0) {
Write-Host 'Congratulations! ".\pkg\*.go" is safely isolated from internal code.'
} else {
$e = "`nThese files import internal code: (either directly or indirectly)`n"
$badFiles | %{ $e+=" - $_"}
Throw $e
}
}
# Validates that changed files are correctly go-formatted
Function Validate-GoFormat($headCommit, $upstreamCommit) {
Write-Host "INFO: Validating go formatting on changed files..."
# Verify gofmt is installed
if ($(Get-Command gofmt -ErrorAction SilentlyContinue) -eq $nil) { Throw "gofmt does not appear to be installed" }
# Get a list of all go source-code files which have changed. Ignore exit code on next call - always process regardless
$files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'*.go`'"
$files = $files | Select-String -NotMatch "^vendor/"
$badFiles=@(); $files | %{
# Deliberately ignore error on next line - treat as failed
$content=Invoke-Expression "git show $headCommit`:$_"
# Next set of hoops are to ensure we have LF not CRLF semantics as otherwise gofmt on Windows will not succeed.
# Also note that gofmt on Windows does not appear to support stdin piping correctly. Hence go through a temporary file.
$content=$content -join "`n"
$content+="`n"
$outputFile=[System.IO.Path]::GetTempFileName()
if (Test-Path $outputFile) { Remove-Item $outputFile }
[System.IO.File]::WriteAllText($outputFile, $content, (New-Object System.Text.UTF8Encoding($False)))
$valid=Invoke-Expression "gofmt -s -l $outputFile"
Write-Host "Checking $outputFile"
if ($valid.Length -ne 0) { $badFiles+=$_ }
if (Test-Path $outputFile) { Remove-Item $outputFile }
}
if ($badFiles.Length -eq 0) {
Write-Host 'Congratulations! All Go source files are properly formatted.'
} else {
$e = "`nThese files are not properly gofmt`'d:`n"
$badFiles | %{ $e+=" - $_`n"}
$e+= "`nPlease reformat the above files using `"gofmt -s -w`" and commit the result."
Throw $e
}
}
# Run the unit tests
Function Run-UnitTests() {
Write-Host "INFO: Running unit tests..."
$testPath="./..."
$goListCommand = "go list -e -f '{{if ne .Name """ + '\"github.com/docker/docker\"' + """}}{{.ImportPath}}{{end}}' $testPath"
$pkgList = $(Invoke-Expression $goListCommand)
if ($LASTEXITCODE -ne 0) { Throw "go list for unit tests failed" }
$pkgList = $pkgList | Select-String -Pattern "github.com/docker/docker"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/vendor"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/man"
$pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/integration-cli"
$pkgList = $pkgList -replace "`r`n", " "
$goTestCommand = "go test" + $raceParm + " -cover -ldflags -w -tags """ + "autogen daemon" + """ -a """ + "-test.timeout=10m" + """ $pkgList"
Invoke-Expression $goTestCommand
if ($LASTEXITCODE -ne 0) { Throw "Unit tests failed" }
}
# Start of main code.
Try {
Write-Host -ForegroundColor Cyan "INFO: make.ps1 starting at $(Get-Date)"
$root=$(pwd)
# Handle the "-All" shortcut to turn on all things we can handle.
if ($All) { $Client=$True; $Daemon=$True; $DCO=$True; $PkgImports=$True; $GoFormat=$True; $TestUnit=$True }
# Handle the "-Binary" shortcut to build both client and daemon.
if ($Binary) { $Client = $True; $Daemon = $True }
# Make sure we have something to do
if (-not($Client) -and -not($Daemon) -and -not($DCO) -and -not($PkgImports) -and -not($GoFormat) -and -not($TestUnit)) { Throw 'Nothing to do. Try adding "-All" for everything I can do' }
# Verify git is installed
if ($(Get-Command git -ErrorAction SilentlyContinue) -eq $nil) { Throw "Git does not appear to be installed" }
# Verify go is installed
if ($(Get-Command go -ErrorAction SilentlyContinue) -eq $nil) { Throw "GoLang does not appear to be installed" }
# Get the git commit. This will also verify if we are in a repo or not. Then add a custom string if supplied.
$gitCommit=Get-GitCommit
if ($CommitSuffix -ne "") { $gitCommit += "-"+$CommitSuffix -Replace ' ', '' }
# Get the version of docker (eg 1.14.0-dev)
$dockerVersion=Get-DockerVersion
# Give a warning if we are not running in a container and are building binaries or running unit tests.
# Not relevant for validation tests as these are fine to run outside of a container.
if ($Client -or $Daemon -or $TestUnit) { Check-InContainer }
# Verify GOPATH is set
if ($env:GOPATH.Length -eq 0) { Throw "Missing GOPATH environment variable. See https://golang.org/doc/code.html#GOPATH" }
# Run autogen if building binaries or running unit tests.
if ($Client -or $Daemon -or $TestUnit) {
Write-Host "INFO: Invoking autogen..."
Try { .\hack\make\.go-autogen.ps1 -CommitString $gitCommit -DockerVersion $dockerVersion }
Catch [Exception] { Throw $_ }
}
# DCO, Package import and Go formatting tests.
if ($DCO -or $PkgImports -or $GoFormat) {
# We need the head and upstream commits for these
$headCommit=Get-HeadCommit
$upstreamCommit=Get-UpstreamCommit
# Run DCO validation
if ($DCO) { Validate-DCO $headCommit $upstreamCommit }
# Run `gofmt` validation
if ($GoFormat) { Validate-GoFormat $headCommit $upstreamCommit }
# Run pkg isolation validation
if ($PkgImports) { Validate-PkgImports $headCommit $upstreamCommit }
}
# Build the binaries
if ($Client -or $Daemon) {
# Create the bundles directory if it doesn't exist
if (-not (Test-Path ".\bundles")) { New-Item ".\bundles" -ItemType Directory | Out-Null }
# Perform the actual build
if ($Daemon) { Execute-Build "daemon" "daemon" "dockerd" }
if ($Client) { Execute-Build "client" "" "docker" }
}
# Run unit tests
if ($TestUnit) { Run-UnitTests }
# Gratuitous ASCII art.
if ($Daemon -or $Client) {
Write-Host
Write-Host -ForegroundColor Green " ________ ____ __."
Write-Host -ForegroundColor Green " \_____ \ `| `|/ _`|"
Write-Host -ForegroundColor Green " / `| \`| `<"
Write-Host -ForegroundColor Green " / `| \ `| \"
Write-Host -ForegroundColor Green " \_______ /____`|__ \"
Write-Host -ForegroundColor Green " \/ \/"
Write-Host
}
}
Catch [Exception] {
Write-Host -ForegroundColor Red ("`nERROR: make.ps1 failed:`n$_")
# More gratuitous ASCII art.
Write-Host
Write-Host -ForegroundColor Red "___________ .__.__ .___"
Write-Host -ForegroundColor Red "\_ _____/____ `|__`| `| ____ __`| _/"
Write-Host -ForegroundColor Red " `| __) \__ \ `| `| `| _/ __ \ / __ `| "
Write-Host -ForegroundColor Red " `| \ / __ \`| `| `|_\ ___// /_/ `| "
Write-Host -ForegroundColor Red " \___ / (____ /__`|____/\___ `>____ `| "
Write-Host -ForegroundColor Red " \/ \/ \/ \/ "
Write-Host
}
Finally {
if ($global:pushed) { Pop-Location }
Write-Host -ForegroundColor Cyan "INFO: make.ps1 ended at $(Get-Date)"
}

View file

@ -10,16 +10,11 @@
.PARAMETER DockerVersion
The version such as 1.14.0-dev. This is calculated externally to this script.
.PARAMETER StaticSQLite
A string indicating if the daemon binary is compiled with the SQLite
sources compiled in. This is calculated externally to this script.
#>
param(
[Parameter(Mandatory=$true)][string]$CommitString,
[Parameter(Mandatory=$true)][string]$DockerVersion,
[Parameter(Mandatory=$true)][string]$StaticSQLiteString
[Parameter(Mandatory=$true)][string]$DockerVersion
)
$ErrorActionPreference = "Stop"
@ -48,7 +43,6 @@ const (
GitCommit string = "'+$CommitString+'"
Version string = "'+$DockerVersion+'"
BuildTime string = "'+$buildDateTime+'"
StaticSQLite string = "'+$StaticSQLiteString+'"
)
// AUTOGENERATED FILE; see hack\make\.go-autogen.ps1

View file

@ -3610,8 +3610,8 @@ RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/do
# Switch back to root and double check that worked exactly as we might expect it to
USER root
# Add a "supplementary" group for our dockerio user
RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
# Add a "supplementary" group for our dockerio user
echo 'supplementary:x:1002:dockerio' >> /etc/group
# ... and then go verify that we get it like we expect
@ -7141,41 +7141,6 @@ func (s *DockerSuite) TestBuildNetContainer(c *check.C) {
c.Assert(strings.TrimSpace(host), check.Equals, "foobar")
}
// Test case for #24693
func (s *DockerSuite) TestBuildRunEmptyLineAfterEscape(c *check.C) {
name := "testbuildemptylineafterescape"
_, out, err := buildImageWithOut(name,
`
FROM busybox
RUN echo x \
RUN echo y
RUN echo z
# Comment requires the '#' to start from position 1
# RUN echo w
`, true)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "Step 1/4 : FROM busybox")
c.Assert(out, checker.Contains, "Step 2/4 : RUN echo x")
c.Assert(out, checker.Contains, "Step 3/4 : RUN echo y")
c.Assert(out, checker.Contains, "Step 4/4 : RUN echo z")
// With comment, see #24693
name = "testbuildcommentandemptylineafterescape"
_, out, err = buildImageWithOut(name,
`
FROM busybox
RUN echo grafana && \
echo raintank \
#echo env-load
RUN echo vegeta
`, true)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, "Step 1/3 : FROM busybox")
c.Assert(out, checker.Contains, "Step 2/3 : RUN echo grafana && echo raintank")
c.Assert(out, checker.Contains, "Step 3/3 : RUN echo vegeta")
}
func (s *DockerSuite) TestBuildSquashParent(c *check.C) {
testRequires(c, ExperimentalDaemon)
dockerFile := `

View file

@ -568,8 +568,36 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverOutOfBandDelete(c *c
// simulate out of band volume deletion on plugin level
delete(p.vols, "test")
// test re-create with same driver
out, err = s.d.Cmd("volume", "create", "-d", driverName, "--opt", "foo=bar", "--name", "test")
c.Assert(err, checker.IsNil, check.Commentf(out))
out, err = s.d.Cmd("volume", "inspect", "test")
c.Assert(err, checker.IsNil, check.Commentf(out))
var vs []types.Volume
err = json.Unmarshal([]byte(out), &vs)
c.Assert(err, checker.IsNil)
c.Assert(vs, checker.HasLen, 1)
c.Assert(vs[0].Driver, checker.Equals, driverName)
c.Assert(vs[0].Options, checker.NotNil)
c.Assert(vs[0].Options["foo"], checker.Equals, "bar")
c.Assert(vs[0].Driver, checker.Equals, driverName)
// simulate out of band volume deletion on plugin level
delete(p.vols, "test")
// test create with different driver
out, err = s.d.Cmd("volume", "create", "-d", "local", "--name", "test")
c.Assert(err, checker.IsNil, check.Commentf(out))
out, err = s.d.Cmd("volume", "inspect", "test")
c.Assert(err, checker.IsNil, check.Commentf(out))
vs = nil
err = json.Unmarshal([]byte(out), &vs)
c.Assert(err, checker.IsNil)
c.Assert(vs, checker.HasLen, 1)
c.Assert(vs[0].Options, checker.HasLen, 0)
c.Assert(vs[0].Driver, checker.Equals, "local")
}
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverUnmountOnMountFail(c *check.C) {

View file

@ -417,3 +417,33 @@ func (s *DockerSuite) TestInspectAmpersand(c *check.C) {
out, _ = dockerCmd(c, "inspect", name)
c.Assert(out, checker.Contains, `soanni&rtr`)
}
func (s *DockerSuite) TestInspectPlugin(c *check.C) {
testRequires(c, DaemonIsLinux, Network)
_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", pNameWithTag)
c.Assert(err, checker.IsNil)
out, _, err := dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pNameWithTag)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Equals, pName)
out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pNameWithTag)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Equals, pName)
// Even without tag the inspect still work
out, _, err = dockerCmdWithError("inspect", "--type", "plugin", "--format", "{{.Name}}", pName)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Equals, pName)
out, _, err = dockerCmdWithError("inspect", "--format", "{{.Name}}", pName)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Equals, pName)
_, _, err = dockerCmdWithError("plugin", "disable", pNameWithTag)
c.Assert(err, checker.IsNil)
out, _, err = dockerCmdWithError("plugin", "remove", pNameWithTag)
c.Assert(err, checker.IsNil)
c.Assert(out, checker.Contains, pNameWithTag)
}

View file

@ -62,10 +62,10 @@ func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
name := inspectField(c, newName, "Name")
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name))
result := dockerCmdWithResult("inspect", "-f={{.Name}}", "first_name")
result := dockerCmdWithResult("inspect", "-f={{.Name}}", "--type=container", "first_name")
c.Assert(result, icmd.Matches, icmd.Expected{
ExitCode: 1,
Err: "No such object: first_name",
Err: "No such container: first_name",
})
}

View file

@ -4372,42 +4372,6 @@ func (s *DockerSuite) TestRunVolumeCopyFlag(c *check.C) {
c.Assert(err, checker.NotNil, check.Commentf(out))
}
func (s *DockerSuite) TestRunTooLongHostname(c *check.C) {
// Test case in #21445
hostname1 := "this-is-a-way-too-long-hostname-but-it-should-give-a-nice-error.local"
out, _, err := dockerCmdWithError("run", "--hostname", hostname1, "busybox", "echo", "test")
c.Assert(err, checker.NotNil, check.Commentf("Expected docker run to fail!"))
c.Assert(out, checker.Contains, "invalid hostname format:", check.Commentf("Expected to have 'invalid hostname format:' in the output, get: %s!", out))
// Additional test cases
validHostnames := map[string]string{
"hostname": "hostname",
"host-name": "host-name",
"hostname123": "hostname123",
"123hostname": "123hostname",
"hostname-of-63-bytes-long-should-be-valid-and-without-any-error": "hostname-of-63-bytes-long-should-be-valid-and-without-any-error",
}
for hostname := range validHostnames {
dockerCmd(c, "run", "--hostname", hostname, "busybox", "echo", "test")
}
invalidHostnames := map[string]string{
"^hostname": "invalid hostname format: ^hostname",
"hostname%": "invalid hostname format: hostname%",
"host&name": "invalid hostname format: host&name",
"-hostname": "invalid hostname format: -hostname",
"host_name": "invalid hostname format: host_name",
"hostname-of-64-bytes-long-should-be-invalid-and-be-with-an-error": "invalid hostname format: hostname-of-64-bytes-long-should-be-invalid-and-be-with-an-error",
}
for hostname, expectedError := range invalidHostnames {
out, _, err = dockerCmdWithError("run", "--hostname", hostname, "busybox", "echo", "test")
c.Assert(err, checker.NotNil, check.Commentf("Expected docker run to fail!"))
c.Assert(out, checker.Contains, expectedError, check.Commentf("Expected to have '%s' in the output, get: %s!", expectedError, out))
}
}
// Test case for #21976
func (s *DockerSuite) TestRunDNSInHostMode(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace)

View file

@ -84,7 +84,7 @@ func (pm *Manager) Inspect(refOrID string) (tp types.Plugin, err error) {
return tp, err
}
return tp, fmt.Errorf("no plugin name or ID associated with %q", refOrID)
return tp, fmt.Errorf("no such plugin name or ID associated with %q", refOrID)
}
func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) {

View file

@ -284,56 +284,64 @@ func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]st
func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, error) {
// check the local cache
v, _ := s.getNamed(name)
if v != nil {
vDriverName := v.DriverName()
if driverName != "" && vDriverName != driverName {
// we have what looks like a conflict
// let's see if there are existing refs to this volume, if so we don't need
// to go any further since we can assume the volume is legit.
if len(s.getRefs(name)) > 0 {
return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name)
}
if v == nil {
return nil, nil
}
// looks like there is a conflict, but nothing is referencing it...
// let's check if the found volume ref
// is stale by checking with the driver if it still exists
vd, err := volumedrivers.GetDriver(vDriverName)
if err != nil {
// play it safe and return the error
// TODO(cpuguy83): maybe when when v2 plugins are ubiquitous, we should
// just purge this from the cache
return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
}
vDriverName := v.DriverName()
var conflict bool
if driverName != "" && vDriverName != driverName {
conflict = true
}
// now check if it still exists in the driver
v2, err := vd.Get(name)
err = errors.Cause(err)
if err != nil {
if _, ok := err.(net.Error); ok {
// got some error related to the driver connectivity
// play it safe and return the error
// TODO(cpuguy83): When when v2 plugins are ubiquitous, maybe we should
// just purge this from the cache
return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
}
// let's check if the found volume ref
// is stale by checking with the driver if it still exists
exists, err := volumeExists(v)
if err != nil {
return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
}
// a driver can return whatever it wants, so let's make sure this is nil
if v2 == nil {
// purge this reference from the cache
s.Purge(name)
return nil, nil
}
}
if v2 != nil {
return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name)
}
if exists {
if conflict {
return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name)
}
return v, nil
}
if len(s.getRefs(v.Name())) > 0 {
// Containers are referencing this volume but it doesn't seem to exist anywhere.
// Return a conflict error here, the user can fix this with `docker volume rm -f`
return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName)
}
// doesn't exist, so purge it from the cache
s.Purge(name)
return nil, nil
}
// volumeExists returns if the volume is still present in the driver.
// An error is returned if there was an issue communicating with the driver.
func volumeExists(v volume.Volume) (bool, error) {
vd, err := volumedrivers.GetDriver(v.DriverName())
if err != nil {
return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName())
}
exists, err := vd.Get(v.Name())
if err != nil {
err = errors.Cause(err)
if _, ok := err.(net.Error); ok {
return false, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName())
}
// At this point, the error could be anything from the driver, such as "no such volume"
// Let's not check an error here, and instead check if the driver returned a volume
}
if exists == nil {
return false, nil
}
return true, nil
}
// create asks the given driver to create a volume with the name/opts.
// If a volume with the name is already known, it will ask the stored driver for the volume.
// If the passed in driver name does not match the driver name which is stored
@ -354,6 +362,7 @@ func (s *VolumeStore) create(name, driverName string, opts, labels map[string]st
if err != nil {
return nil, err
}
if v != nil {
return v, nil
}