mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue