Merge pull request #29094 from vieux/1.13.0-rc3-cherrypicks
1.13.0-rc3 cherry-picks: part3
This commit is contained in:
commit
3ac2991ff8
39 changed files with 782 additions and 293 deletions
|
@ -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 . .
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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.* \
|
||||
|
|
|
@ -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.* \
|
||||
|
|
|
@ -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.* \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
(from "busybox")
|
||||
(run "foo")
|
||||
(bar "")
|
|
@ -6,7 +6,9 @@ RUN apt-get \update && \
|
|||
ADD \conf\\" /.znc
|
||||
|
||||
RUN foo \
|
||||
|
||||
bar \
|
||||
|
||||
baz
|
||||
|
||||
CMD [ "\/usr\\\"/bin/znc", "-f", "-r" ]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
401
hack/make.ps1
Normal 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)"
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 := `
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue