2014-10-14 17:32:25 -04:00
package main
import (
2015-05-01 18:01:10 -04:00
"archive/tar"
2014-10-14 17:32:25 -04:00
"bytes"
"encoding/json"
2015-07-24 17:12:55 -04:00
"fmt"
2014-10-14 17:32:25 -04:00
"io"
2015-04-14 04:00:46 -04:00
"net/http"
2015-04-29 13:48:30 -04:00
"net/http/httputil"
2015-07-24 17:12:55 -04:00
"net/url"
2015-05-03 08:54:55 -04:00
"os"
2015-11-26 07:14:09 -05:00
"regexp"
2015-06-12 12:49:53 -04:00
"strconv"
2014-12-12 11:01:05 -05:00
"strings"
2015-01-19 19:10:26 -05:00
"time"
2015-04-11 17:49:14 -04:00
2015-09-09 09:36:44 -04:00
"github.com/docker/docker/pkg/integration"
2015-11-18 19:37:42 -05:00
"github.com/docker/docker/pkg/integration/checker"
2015-04-11 17:49:14 -04:00
"github.com/docker/docker/pkg/stringid"
2016-01-04 19:05:26 -05:00
"github.com/docker/engine-api/types"
containertypes "github.com/docker/engine-api/types/container"
2016-01-21 17:24:35 -05:00
networktypes "github.com/docker/engine-api/types/network"
2015-04-18 12:46:47 -04:00
"github.com/go-check/check"
2014-10-14 17:32:25 -04:00
)
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiGetAll ( c * check . C ) {
2014-10-14 17:32:25 -04:00
startCount , err := getContainerCount ( )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "Cannot query container count" ) )
2014-10-14 17:32:25 -04:00
2014-10-21 18:48:32 -04:00
name := "getall"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "true" )
2014-10-14 17:32:25 -04:00
2015-04-20 17:03:56 -04:00
status , body , err := sockRequest ( "GET" , "/containers/json?all=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2014-10-14 17:32:25 -04:00
2014-10-21 18:48:32 -04:00
var inspectJSON [ ] struct {
Names [ ] string
}
2015-11-18 19:37:42 -05:00
err = json . Unmarshal ( body , & inspectJSON )
c . Assert ( err , checker . IsNil , check . Commentf ( "unable to unmarshal response body" ) )
2014-10-14 17:32:25 -04:00
2015-11-18 19:37:42 -05:00
c . Assert ( inspectJSON , checker . HasLen , startCount + 1 )
2014-10-21 18:48:32 -04:00
2015-11-18 19:37:42 -05:00
actual := inspectJSON [ 0 ] . Names [ 0 ]
c . Assert ( actual , checker . Equals , "/" + name )
2014-10-14 17:32:25 -04:00
}
2015-06-03 12:23:14 -04:00
// regression test for empty json field being omitted #13691
func ( s * DockerSuite ) TestContainerApiGetJSONNoFieldsOmitted ( c * check . C ) {
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "busybox" , "true" )
2015-06-03 12:23:14 -04:00
status , body , err := sockRequest ( "GET" , "/containers/json?all=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-06-03 12:23:14 -04:00
// empty Labels field triggered this bug, make sense to check for everything
// cause even Ports for instance can trigger this bug
// better safe than sorry..
fields := [ ] string {
"Id" ,
"Names" ,
"Image" ,
"Command" ,
"Created" ,
"Ports" ,
"Labels" ,
"Status" ,
Add containers’ networks to /containers/json
After addition of multi-host networking in Docker 1.9, Docker Remote
API is still returning only the network specified during creation
of the container in the “List Containers” (`/containers/json`) endpoint:
...
"HostConfig": {
"NetworkMode": "default"
},
The list of networks containers are attached to is only available at
Get Container (`/containers/<id>/json`) endpoint.
This does not allow applications utilizing multi-host networking to
be built on top of Docker Remote API.
Therefore I added a simple `"NetworkSettings"` section to the
`/containers/json` endpoint. This is not identical to the NetworkSettings
returned in Get Container (`/containers/<id>/json`) endpoint. It only
contains a single field `"Networks"`, which is essentially the same
value shown in inspect output of a container.
This change adds the following section to the `/containers/json`:
"NetworkSettings": {
"Networks": {
"bridge": {
"EndpointID": "2cdc4edb1ded3631c81f57966563e...",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02"
}
}
}
This is of type `SummaryNetworkSettings` type, a minimal version of
`api/types#NetworkSettings`.
Actually all I need is the network name and the IPAddress fields. If folks
find this addition too big, I can create a `SummaryEndpointSettings` field
as well, containing just the IPAddress field.
Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
2015-12-09 23:48:50 -05:00
"NetworkSettings" ,
2015-06-03 12:23:14 -04:00
}
// decoding into types.Container do not work since it eventually unmarshal
// and empty field to an empty go map, so we just check for a string
for _ , f := range fields {
if ! strings . Contains ( string ( body ) , f ) {
c . Fatalf ( "Field %s is missing and it shouldn't" , f )
}
}
}
2015-06-12 12:49:53 -04:00
type containerPs struct {
Names [ ] string
Ports [ ] map [ string ] interface { }
}
// regression test for non-empty fields from #13901
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestContainerApiPsOmitFields ( c * check . C ) {
// Problematic for Windows porting due to networking not yet being passed back
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-06-12 12:49:53 -04:00
name := "pstest"
port := 80
2016-01-26 23:16:36 -05:00
runSleepingContainer ( c , "--name" , name , "--expose" , strconv . Itoa ( port ) )
2015-06-12 12:49:53 -04:00
status , body , err := sockRequest ( "GET" , "/containers/json?all=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-06-12 12:49:53 -04:00
var resp [ ] containerPs
err = json . Unmarshal ( body , & resp )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-12 12:49:53 -04:00
var foundContainer * containerPs
for _ , container := range resp {
for _ , testName := range container . Names {
if "/" + name == testName {
foundContainer = & container
break
}
}
}
2015-11-18 19:37:42 -05:00
c . Assert ( foundContainer . Ports , checker . HasLen , 1 )
c . Assert ( foundContainer . Ports [ 0 ] [ "PrivatePort" ] , checker . Equals , float64 ( port ) )
2015-06-12 12:49:53 -04:00
_ , ok := foundContainer . Ports [ 0 ] [ "PublicPort" ]
2015-11-18 19:37:42 -05:00
c . Assert ( ok , checker . Not ( checker . Equals ) , true )
2015-06-12 12:49:53 -04:00
_ , ok = foundContainer . Ports [ 0 ] [ "IP" ]
2015-11-18 19:37:42 -05:00
c . Assert ( ok , checker . Not ( checker . Equals ) , true )
2015-06-12 12:49:53 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiGetExport ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO: Investigate why this fails on Windows to Windows CI
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2014-10-21 18:48:32 -04:00
name := "exportcontainer"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "touch" , "/test" )
2014-10-14 17:32:25 -04:00
2015-04-20 17:03:56 -04:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/export" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2014-10-14 17:32:25 -04:00
found := false
for tarReader := tar . NewReader ( bytes . NewReader ( body ) ) ; ; {
h , err := tarReader . Next ( )
2015-11-18 19:37:42 -05:00
if err != nil && err == io . EOF {
break
2014-10-14 17:32:25 -04:00
}
if h . Name == "test" {
found = true
break
}
}
2015-11-18 19:37:42 -05:00
c . Assert ( found , checker . True , check . Commentf ( "The created test file has not been found in the exported image" ) )
2014-10-14 17:32:25 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiGetChanges ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Not supported on Windows as Windows does not support docker diff (/containers/name/changes)
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2014-10-21 18:48:32 -04:00
name := "changescontainer"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "rm" , "/etc/passwd" )
2014-10-14 17:32:25 -04:00
2015-04-20 17:03:56 -04:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/changes" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2014-10-14 17:32:25 -04:00
changes := [ ] struct {
Kind int
Path string
} { }
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & changes ) , checker . IsNil , check . Commentf ( "unable to unmarshal response body" ) )
2014-10-14 17:32:25 -04:00
// Check the changelog for removal of /etc/passwd
success := false
for _ , elem := range changes {
if elem . Path == "/etc/passwd" && elem . Kind == 2 {
success = true
}
}
2015-11-18 19:37:42 -05:00
c . Assert ( success , checker . True , check . Commentf ( "/etc/passwd has been removed but is not present in the diff" ) )
2014-10-14 17:32:25 -04:00
}
2014-12-12 11:01:05 -05:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiStartVolumeBinds ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows CI: Investigate further why this fails on Windows to Windows CI.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2016-01-23 14:04:57 -05:00
path := "/foo"
if daemonPlatform == "windows" {
path = ` c:\foo `
}
2014-12-12 11:01:05 -05:00
name := "testing"
config := map [ string ] interface { } {
"Image" : "busybox" ,
2016-01-23 14:04:57 -05:00
"Volumes" : map [ string ] struct { } { path : { } } ,
2014-12-12 11:01:05 -05:00
}
2015-04-20 17:03:56 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2014-12-12 11:01:05 -05:00
2015-09-24 13:53:47 -04:00
bindPath := randomTmpDirPath ( "test" , daemonPlatform )
2014-12-12 11:01:05 -05:00
config = map [ string ] interface { } {
2016-01-23 14:04:57 -05:00
"Binds" : [ ] string { bindPath + ":" + path } ,
2014-12-12 11:01:05 -05:00
}
2015-04-20 17:03:56 -04:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2014-12-12 11:01:05 -05:00
2016-01-23 14:04:57 -05:00
pth , err := inspectMountSourceField ( name , path )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( pth , checker . Equals , bindPath , check . Commentf ( "expected volume host path to be %s, got %s" , bindPath , pth ) )
2014-12-12 11:01:05 -05:00
}
2015-02-09 11:17:41 -05:00
// Test for GH#10618
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiStartDupVolumeBinds ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI - Port this
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-02-09 11:17:41 -05:00
name := "testdups"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { "/tmp" : { } } ,
}
2015-04-20 17:03:56 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-02-09 11:17:41 -05:00
2015-09-24 13:53:47 -04:00
bindPath1 := randomTmpDirPath ( "test1" , daemonPlatform )
bindPath2 := randomTmpDirPath ( "test2" , daemonPlatform )
2015-02-09 11:17:41 -05:00
config = map [ string ] interface { } {
"Binds" : [ ] string { bindPath1 + ":/tmp" , bindPath2 + ":/tmp" } ,
}
2015-04-20 17:03:56 -04:00
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/start" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
2015-12-01 13:39:34 -05:00
c . Assert ( string ( body ) , checker . Contains , "Duplicate mount point" , check . Commentf ( "Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v" , string ( body ) , err ) )
2015-02-09 11:17:41 -05:00
}
2015-04-20 17:03:56 -04:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiStartVolumesFrom ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI - Port this
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2014-12-12 11:01:05 -05:00
volName := "voltst"
volPath := "/tmp"
2016-02-28 05:47:37 -05:00
dockerCmd ( c , "run" , "--name" , volName , "-v" , volPath , "busybox" )
2014-12-12 11:01:05 -05:00
2015-06-03 15:21:38 -04:00
name := "TestContainerApiStartVolumesFrom"
2014-12-12 11:01:05 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { volPath : { } } ,
}
2015-04-20 17:03:56 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2014-12-12 11:01:05 -05:00
config = map [ string ] interface { } {
"VolumesFrom" : [ ] string { volName } ,
}
2015-04-20 17:03:56 -04:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2014-12-12 11:01:05 -05:00
2015-06-03 15:21:38 -04:00
pth , err := inspectMountSourceField ( name , volPath )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-03 15:21:38 -04:00
pth2 , err := inspectMountSourceField ( volName , volPath )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( pth , checker . Equals , pth2 , check . Commentf ( "expected volume host path to be %s, got %s" , pth , pth2 ) )
2014-12-12 11:01:05 -05:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestGetContainerStats ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support stats
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-01-21 15:14:28 -05:00
var (
2015-07-14 02:35:36 -04:00
name = "statscontainer"
2015-01-21 15:14:28 -05:00
)
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "-d" , "--name" , name , "busybox" , "top" )
2015-01-21 15:14:28 -05:00
type b struct {
2015-04-27 13:29:48 -04:00
status int
body [ ] byte
err error
2015-01-21 15:14:28 -05:00
}
bc := make ( chan b , 1 )
2015-01-19 19:10:26 -05:00
go func ( ) {
2015-04-20 17:03:56 -04:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/stats" , nil )
2015-04-27 13:29:48 -04:00
bc <- b { status , body , err }
2015-01-19 19:10:26 -05:00
} ( )
2015-01-21 15:14:28 -05:00
// allow some time to stream the stats from the container
time . Sleep ( 4 * time . Second )
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "rm" , "-f" , name )
2015-01-19 19:10:26 -05:00
2015-01-21 15:14:28 -05:00
// collect the results from the stats stream or timeout and fail
// if the stream was not disconnected.
select {
case <- time . After ( 2 * time . Second ) :
2015-04-18 12:46:47 -04:00
c . Fatal ( "stream was not closed after container was removed" )
2015-01-21 15:14:28 -05:00
case sr := <- bc :
2015-11-18 19:37:42 -05:00
c . Assert ( sr . err , checker . IsNil )
c . Assert ( sr . status , checker . Equals , http . StatusOK )
2015-01-21 15:14:28 -05:00
dec := json . NewDecoder ( bytes . NewBuffer ( sr . body ) )
2015-02-24 13:47:47 -05:00
var s * types . Stats
2015-01-21 15:14:28 -05:00
// decode only one object from the stream
2015-11-18 19:37:42 -05:00
c . Assert ( dec . Decode ( & s ) , checker . IsNil )
2015-01-19 19:10:26 -05:00
}
}
2015-01-21 14:08:19 -05:00
2015-05-23 10:09:39 -04:00
func ( s * DockerSuite ) TestGetContainerStatsRmRunning ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support stats
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-26 22:22:03 -04:00
out , _ := dockerCmd ( c , "run" , "-d" , "busybox" , "top" )
id := strings . TrimSpace ( out )
2015-09-09 09:36:44 -04:00
buf := & integration . ChannelBuffer { make ( chan [ ] byte , 1 ) }
2015-05-26 22:22:03 -04:00
defer buf . Close ( )
2016-01-29 22:27:27 -05:00
chErr := make ( chan error , 1 )
2015-05-26 22:22:03 -04:00
go func ( ) {
_ , body , err := sockRequestRaw ( "GET" , "/containers/" + id + "/stats?stream=1" , nil , "application/json" )
if err != nil {
chErr <- err
}
defer body . Close ( )
_ , err = io . Copy ( buf , body )
chErr <- err
} ( )
defer func ( ) {
2016-01-29 22:27:27 -05:00
select {
case err := <- chErr :
c . Assert ( err , checker . IsNil )
default :
return
}
2015-05-26 22:22:03 -04:00
} ( )
b := make ( [ ] byte , 32 )
// make sure we've got some stats
_ , err := buf . ReadTimeout ( b , 2 * time . Second )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-05-26 22:22:03 -04:00
// Now remove without `-f` and make sure we are still pulling stats
2015-07-27 14:13:25 -04:00
_ , _ , err = dockerCmdWithError ( "rm" , id )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . Not ( checker . IsNil ) , check . Commentf ( "rm should have failed but didn't" ) )
2015-05-26 22:22:03 -04:00
_ , err = buf . ReadTimeout ( b , 2 * time . Second )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-05-26 22:22:03 -04:00
2016-01-29 22:27:27 -05:00
dockerCmd ( c , "kill" , id )
2015-05-26 22:22:03 -04:00
}
2015-05-23 10:09:39 -04:00
// regression test for gh13421
// previous test was just checking one stat entry so it didn't fail (stats with
// stream false always return one stat)
func ( s * DockerSuite ) TestGetContainerStatsStream ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support stats
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-23 10:09:39 -04:00
name := "statscontainer"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "-d" , "--name" , name , "busybox" , "top" )
2015-05-23 10:09:39 -04:00
type b struct {
status int
body [ ] byte
err error
}
bc := make ( chan b , 1 )
go func ( ) {
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/stats" , nil )
bc <- b { status , body , err }
} ( )
// allow some time to stream the stats from the container
time . Sleep ( 4 * time . Second )
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "rm" , "-f" , name )
2015-05-23 10:09:39 -04:00
// collect the results from the stats stream or timeout and fail
// if the stream was not disconnected.
select {
case <- time . After ( 2 * time . Second ) :
c . Fatal ( "stream was not closed after container was removed" )
case sr := <- bc :
2015-11-18 19:37:42 -05:00
c . Assert ( sr . err , checker . IsNil )
c . Assert ( sr . status , checker . Equals , http . StatusOK )
2015-05-23 10:09:39 -04:00
s := string ( sr . body )
// count occurrences of "read" of types.Stats
if l := strings . Count ( s , "read" ) ; l < 2 {
c . Fatalf ( "Expected more than one stat streamed, got %d" , l )
}
}
}
func ( s * DockerSuite ) TestGetContainerStatsNoStream ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support stats
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-23 10:09:39 -04:00
name := "statscontainer"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "-d" , "--name" , name , "busybox" , "top" )
2015-05-23 10:09:39 -04:00
type b struct {
status int
body [ ] byte
err error
}
bc := make ( chan b , 1 )
go func ( ) {
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/stats?stream=0" , nil )
bc <- b { status , body , err }
} ( )
// allow some time to stream the stats from the container
time . Sleep ( 4 * time . Second )
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "rm" , "-f" , name )
2015-05-23 10:09:39 -04:00
// collect the results from the stats stream or timeout and fail
// if the stream was not disconnected.
select {
case <- time . After ( 2 * time . Second ) :
c . Fatal ( "stream was not closed after container was removed" )
case sr := <- bc :
2015-11-18 19:37:42 -05:00
c . Assert ( sr . err , checker . IsNil )
c . Assert ( sr . status , checker . Equals , http . StatusOK )
2015-05-23 10:09:39 -04:00
s := string ( sr . body )
// count occurrences of "read" of types.Stats
2015-11-18 19:37:42 -05:00
c . Assert ( strings . Count ( s , "read" ) , checker . Equals , 1 , check . Commentf ( "Expected only one stat streamed, got %d" , strings . Count ( s , "read" ) ) )
2015-05-23 10:09:39 -04:00
}
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestGetStoppedContainerStats ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support stats
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-12-29 23:29:31 -05:00
name := "statscontainer"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "create" , "--name" , name , "busybox" , "top" )
2015-03-16 07:55:34 -04:00
2015-12-29 23:29:31 -05:00
type stats struct {
status int
err error
}
chResp := make ( chan stats )
// We expect an immediate response, but if it's not immediate, the test would hang, so put it in a goroutine
// below we'll check this on a timeout.
2015-03-16 07:55:34 -04:00
go func ( ) {
2015-12-29 23:29:31 -05:00
resp , body , err := sockRequestRaw ( "GET" , "/containers/" + name + "/stats" , nil , "" )
body . Close ( )
chResp <- stats { resp . StatusCode , err }
2015-03-16 07:55:34 -04:00
} ( )
2015-12-29 23:29:31 -05:00
select {
case r := <- chResp :
c . Assert ( r . err , checker . IsNil )
c . Assert ( r . status , checker . Equals , http . StatusOK )
case <- time . After ( 10 * time . Second ) :
2016-02-22 14:22:20 -05:00
c . Fatal ( "timeout waiting for stats response for stopped container" )
2015-12-29 23:29:31 -05:00
}
2015-03-16 07:55:34 -04:00
}
2015-01-26 17:31:30 -05:00
// #9981 - Allow a docker created volume (ie, one in /var/lib/docker/volumes) to be used to overwrite (via passing in Binds on api start) an existing volume
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestPostContainerBindNormalVolume ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI - Port this
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "create" , "-v" , "/foo" , "--name=one" , "busybox" )
2015-01-26 17:31:30 -05:00
2015-06-03 15:21:38 -04:00
fooDir , err := inspectMountSourceField ( "one" , "/foo" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-01-26 17:31:30 -05:00
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "create" , "-v" , "/foo" , "--name=two" , "busybox" )
2015-01-26 17:31:30 -05:00
bindSpec := map [ string ] [ ] string { "Binds" : { fooDir + ":/foo" } }
2015-04-20 17:03:56 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/two/start" , bindSpec )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-01-26 17:31:30 -05:00
2015-06-03 15:21:38 -04:00
fooDir2 , err := inspectMountSourceField ( "two" , "/foo" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( fooDir2 , checker . Equals , fooDir , check . Commentf ( "expected volume path to be %s, got: %s" , fooDir , fooDir2 ) )
2015-01-26 17:31:30 -05:00
}
2015-04-09 21:14:01 -04:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiPause ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support pause
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-09 21:14:01 -04:00
defer unpauseAllContainers ( )
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "run" , "-d" , "busybox" , "sleep" , "30" )
2015-04-09 21:14:01 -04:00
ContainerID := strings . TrimSpace ( out )
2015-04-20 17:03:56 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/" + ContainerID + "/pause" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-04-09 21:14:01 -04:00
pausedContainers , err := getSliceOfPausedContainers ( )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "error thrown while checking if containers were paused" ) )
2015-04-09 21:14:01 -04:00
if len ( pausedContainers ) != 1 || stringid . TruncateID ( ContainerID ) != pausedContainers [ 0 ] {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "there should be one paused container and not %d" , len ( pausedContainers ) )
2015-04-09 21:14:01 -04:00
}
2015-04-20 17:03:56 -04:00
status , _ , err = sockRequest ( "POST" , "/containers/" + ContainerID + "/unpause" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-04-09 21:14:01 -04:00
pausedContainers , err = getSliceOfPausedContainers ( )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "error thrown while checking if containers were paused" ) )
c . Assert ( pausedContainers , checker . IsNil , check . Commentf ( "There should be no paused container." ) )
2015-04-09 21:14:01 -04:00
}
2015-04-14 17:14:29 -04:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiTop ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Problematic on Windows as Windows does not support top
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "run" , "-d" , "busybox" , "/bin/sh" , "-c" , "top" )
2015-04-18 12:46:47 -04:00
id := strings . TrimSpace ( string ( out ) )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-04-14 17:14:29 -04:00
type topResp struct {
Titles [ ] string
Processes [ ] [ ] string
}
var top topResp
2015-04-20 17:03:56 -04:00
status , b , err := sockRequest ( "GET" , "/containers/" + id + "/top?ps_args=aux" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
c . Assert ( json . Unmarshal ( b , & top ) , checker . IsNil )
c . Assert ( top . Titles , checker . HasLen , 11 , check . Commentf ( "expected 11 titles, found %d: %v" , len ( top . Titles ) , top . Titles ) )
2015-04-14 17:14:29 -04:00
if top . Titles [ 0 ] != "USER" || top . Titles [ 10 ] != "COMMAND" {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v" , top . Titles )
2015-04-14 17:14:29 -04:00
}
2015-11-18 19:37:42 -05:00
c . Assert ( top . Processes , checker . HasLen , 2 , check . Commentf ( "expected 2 processes, found %d: %v" , len ( top . Processes ) , top . Processes ) )
c . Assert ( top . Processes [ 0 ] [ 10 ] , checker . Equals , "/bin/sh -c top" )
c . Assert ( top . Processes [ 1 ] [ 10 ] , checker . Equals , "top" )
2015-04-14 17:14:29 -04:00
}
2015-04-14 20:48:03 -04:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiCommit ( c * check . C ) {
2015-04-25 08:46:47 -04:00
cName := "testapicommit"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name=" + cName , "busybox" , "/bin/sh" , "-c" , "touch /test" )
2015-04-14 20:48:03 -04:00
2015-11-18 17:20:54 -05:00
name := "testcontainerapicommit"
2015-04-25 08:46:47 -04:00
status , b , err := sockRequest ( "POST" , "/commit?repo=" + name + "&testtag=tag&container=" + cName , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-14 20:48:03 -04:00
type resp struct {
2015-07-22 08:59:24 -04:00
ID string
2015-04-14 20:48:03 -04:00
}
var img resp
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( b , & img ) , checker . IsNil )
2015-04-14 20:48:03 -04:00
2016-01-28 09:19:25 -05:00
cmd := inspectField ( c , img . ID , "Config.Cmd" )
2016-02-29 06:28:37 -05:00
c . Assert ( cmd , checker . Equals , "[/bin/sh -c touch /test]" , check . Commentf ( "got wrong Cmd from commit: %q" , cmd ) )
2015-11-18 19:37:42 -05:00
2015-04-14 20:48:03 -04:00
// sanity check, make sure the image is what we think it is
2015-07-22 08:59:24 -04:00
dockerCmd ( c , "run" , img . ID , "ls" , "/test" )
2015-05-30 05:31:51 -04:00
}
func ( s * DockerSuite ) TestContainerApiCommitWithLabelInConfig ( c * check . C ) {
cName := "testapicommitwithconfig"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name=" + cName , "busybox" , "/bin/sh" , "-c" , "touch /test" )
2015-05-30 05:31:51 -04:00
config := map [ string ] interface { } {
"Labels" : map [ string ] string { "key1" : "value1" , "key2" : "value2" } ,
}
2015-11-18 17:20:54 -05:00
name := "testcontainerapicommitwithconfig"
2015-05-30 05:31:51 -04:00
status , b , err := sockRequest ( "POST" , "/commit?repo=" + name + "&container=" + cName , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-05-30 05:31:51 -04:00
type resp struct {
2015-07-22 08:59:24 -04:00
ID string
2015-05-30 05:31:51 -04:00
}
var img resp
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( b , & img ) , checker . IsNil )
2015-05-30 05:31:51 -04:00
2016-01-28 09:19:25 -05:00
label1 := inspectFieldMap ( c , img . ID , "Config.Labels" , "key1" )
2015-11-18 19:37:42 -05:00
c . Assert ( label1 , checker . Equals , "value1" )
2015-05-30 05:31:51 -04:00
2016-01-28 09:19:25 -05:00
label2 := inspectFieldMap ( c , img . ID , "Config.Labels" , "key2" )
2015-11-18 19:37:42 -05:00
c . Assert ( label2 , checker . Equals , "value2" )
2015-05-30 05:31:51 -04:00
2016-01-28 09:19:25 -05:00
cmd := inspectField ( c , img . ID , "Config.Cmd" )
2016-02-29 06:28:37 -05:00
c . Assert ( cmd , checker . Equals , "[/bin/sh -c touch /test]" , check . Commentf ( "got wrong Cmd from commit: %q" , cmd ) )
2015-05-30 05:31:51 -04:00
// sanity check, make sure the image is what we think it is
2015-07-22 08:59:24 -04:00
dockerCmd ( c , "run" , img . ID , "ls" , "/test" )
2015-04-14 20:48:03 -04:00
}
2015-04-14 21:04:43 -04:00
2015-07-15 23:45:48 -04:00
func ( s * DockerSuite ) TestContainerApiBadPort ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI - Port this test
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-15 23:45:48 -04:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Cmd" : [ ] string { "/bin/sh" , "-c" , "echo test" } ,
"PortBindings" : map [ string ] interface { } {
"8080/tcp" : [ ] map [ string ] interface { } {
{
2015-07-21 09:43:32 -04:00
"HostIP" : "" ,
2015-07-15 23:45:48 -04:00
"HostPort" : "aa80" ,
} ,
} ,
} ,
}
jsonData := bytes . NewBuffer ( nil )
json . NewEncoder ( jsonData ) . Encode ( config )
status , b , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
c . Assert ( strings . TrimSpace ( string ( b ) ) , checker . Equals , ` Invalid port specification: "aa80" ` , check . Commentf ( "Incorrect error msg: %s" , string ( b ) ) )
2015-07-15 23:45:48 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiCreate ( c * check . C ) {
2015-04-14 21:04:43 -04:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Cmd" : [ ] string { "/bin/sh" , "-c" , "touch /test && ls /test" } ,
}
2015-04-20 17:03:56 -04:00
status , b , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-20 17:03:56 -04:00
2015-04-14 21:04:43 -04:00
type createResp struct {
2015-07-22 08:59:24 -04:00
ID string
2015-04-14 21:04:43 -04:00
}
var container createResp
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( b , & container ) , checker . IsNil )
2015-04-14 21:04:43 -04:00
2015-07-22 08:59:24 -04:00
out , _ := dockerCmd ( c , "start" , "-a" , container . ID )
2015-11-18 19:37:42 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "/test" )
2015-04-14 21:04:43 -04:00
}
2015-04-14 21:55:04 -04:00
2015-06-06 12:41:42 -04:00
func ( s * DockerSuite ) TestContainerApiCreateEmptyConfig ( c * check . C ) {
config := map [ string ] interface { } { }
status , b , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
2015-06-06 12:41:42 -04:00
expected := "Config cannot be empty in order to create a container\n"
2015-11-18 19:37:42 -05:00
c . Assert ( string ( b ) , checker . Equals , expected )
2015-06-06 12:41:42 -04:00
}
2016-01-21 17:24:35 -05:00
func ( s * DockerSuite ) TestContainerApiCreateMultipleNetworksConfig ( c * check . C ) {
// Container creation must fail if client specified configurations for more than one network
config := map [ string ] interface { } {
"Image" : "busybox" ,
"NetworkingConfig" : networktypes . NetworkingConfig {
EndpointsConfig : map [ string ] * networktypes . EndpointSettings {
"net1" : { } ,
"net2" : { } ,
"net3" : { } ,
} ,
} ,
}
status , b , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusBadRequest )
// network name order in error message is not deterministic
Remove static errors from errors package.
Moving all strings to the errors package wasn't a good idea after all.
Our custom implementation of Go errors predates everything that's nice
and good about working with errors in Go. Take as an example what we
have to do to get an error message:
```go
func GetErrorMessage(err error) string {
switch err.(type) {
case errcode.Error:
e, _ := err.(errcode.Error)
return e.Message
case errcode.ErrorCode:
ec, _ := err.(errcode.ErrorCode)
return ec.Message()
default:
return err.Error()
}
}
```
This goes against every good practice for Go development. The language already provides a simple, intuitive and standard way to get error messages, that is calling the `Error()` method from an error. Reinventing the error interface is a mistake.
Our custom implementation also makes very hard to reason about errors, another nice thing about Go. I found several (>10) error declarations that we don't use anywhere. This is a clear sign about how little we know about the errors we return. I also found several error usages where the number of arguments was different than the parameters declared in the error, another clear example of how difficult is to reason about errors.
Moreover, our custom implementation didn't really make easier for people to return custom HTTP status code depending on the errors. Again, it's hard to reason about when to set custom codes and how. Take an example what we have to do to extract the message and status code from an error before returning a response from the API:
```go
switch err.(type) {
case errcode.ErrorCode:
daError, _ := err.(errcode.ErrorCode)
statusCode = daError.Descriptor().HTTPStatusCode
errMsg = daError.Message()
case errcode.Error:
// For reference, if you're looking for a particular error
// then you can do something like :
// import ( derr "github.com/docker/docker/errors" )
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
daError, _ := err.(errcode.Error)
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
errMsg = daError.Message
default:
// This part of will be removed once we've
// converted everything over to use the errcode package
// FIXME: this is brittle and should not be necessary.
// If we need to differentiate between different possible error types,
// we should create appropriate error types with clearly defined meaning
errStr := strings.ToLower(err.Error())
for keyword, status := range map[string]int{
"not found": http.StatusNotFound,
"no such": http.StatusNotFound,
"bad parameter": http.StatusBadRequest,
"conflict": http.StatusConflict,
"impossible": http.StatusNotAcceptable,
"wrong login/password": http.StatusUnauthorized,
"hasn't been activated": http.StatusForbidden,
} {
if strings.Contains(errStr, keyword) {
statusCode = status
break
}
}
}
```
You can notice two things in that code:
1. We have to explain how errors work, because our implementation goes against how easy to use Go errors are.
2. At no moment we arrived to remove that `switch` statement that was the original reason to use our custom implementation.
This change removes all our status errors from the errors package and puts them back in their specific contexts.
IT puts the messages back with their contexts. That way, we know right away when errors used and how to generate their messages.
It uses custom interfaces to reason about errors. Errors that need to response with a custom status code MUST implementent this simple interface:
```go
type errorWithStatus interface {
HTTPErrorStatusCode() int
}
```
This interface is very straightforward to implement. It also preserves Go errors real behavior, getting the message is as simple as using the `Error()` method.
I included helper functions to generate errors that use custom status code in `errors/errors.go`.
By doing this, we remove the hard dependency we have eeverywhere to our custom errors package. Yes, you can use it as a helper to generate error, but it's still very easy to generate errors without it.
Please, read this fantastic blog post about errors in Go: http://dave.cheney.net/2014/12/24/inspecting-errors
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-25 10:53:35 -05:00
c . Assert ( string ( b ) , checker . Contains , "Container cannot be connected to network endpoints" )
2016-01-21 17:24:35 -05:00
c . Assert ( string ( b ) , checker . Contains , "net1" )
c . Assert ( string ( b ) , checker . Contains , "net2" )
c . Assert ( string ( b ) , checker . Contains , "net3" )
}
2015-04-22 07:03:57 -04:00
func ( s * DockerSuite ) TestContainerApiCreateWithHostName ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Port this test once hostname is supported
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-25 04:53:38 -04:00
hostName := "test-host"
2015-04-22 07:03:57 -04:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Hostname" : hostName ,
}
2015-04-25 04:53:38 -04:00
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-25 04:53:38 -04:00
var container types . ContainerCreateResponse
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & container ) , checker . IsNil )
2015-04-25 04:53:38 -04:00
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-04-25 04:53:38 -04:00
var containerJSON types . ContainerJSON
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & containerJSON ) , checker . IsNil )
c . Assert ( containerJSON . Config . Hostname , checker . Equals , hostName , check . Commentf ( "Mismatched Hostname" ) )
2015-04-25 04:53:38 -04:00
}
func ( s * DockerSuite ) TestContainerApiCreateWithDomainName ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Port this test once domain name is supported
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-25 04:53:38 -04:00
domainName := "test-domain"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Domainname" : domainName ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-25 04:53:38 -04:00
var container types . ContainerCreateResponse
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & container ) , checker . IsNil )
2015-04-25 04:53:38 -04:00
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-04-25 04:53:38 -04:00
var containerJSON types . ContainerJSON
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & containerJSON ) , checker . IsNil )
c . Assert ( containerJSON . Config . Domainname , checker . Equals , domainName , check . Commentf ( "Mismatched Domainname" ) )
2015-04-25 04:53:38 -04:00
}
2015-04-22 07:03:57 -04:00
2016-01-07 22:43:11 -05:00
func ( s * DockerSuite ) TestContainerApiCreateBridgeNetworkMode ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows does not support bridge
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-25 04:53:38 -04:00
UtilCreateNetworkMode ( c , "bridge" )
2016-01-07 22:43:11 -05:00
}
func ( s * DockerSuite ) TestContainerApiCreateOtherNetworkModes ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows does not support these network modes
2016-01-07 22:43:11 -05:00
testRequires ( c , DaemonIsLinux , NotUserNamespace )
UtilCreateNetworkMode ( c , "host" )
2015-04-25 04:53:38 -04:00
UtilCreateNetworkMode ( c , "container:web1" )
}
2015-04-22 07:03:57 -04:00
2015-04-25 04:53:38 -04:00
func UtilCreateNetworkMode ( c * check . C , networkMode string ) {
config := map [ string ] interface { } {
"Image" : "busybox" ,
"HostConfig" : map [ string ] interface { } { "NetworkMode" : networkMode } ,
2015-04-22 07:03:57 -04:00
}
2015-04-25 04:53:38 -04:00
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-25 04:53:38 -04:00
var container types . ContainerCreateResponse
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & container ) , checker . IsNil )
2015-04-22 07:03:57 -04:00
2015-04-25 04:53:38 -04:00
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-04-25 04:53:38 -04:00
var containerJSON types . ContainerJSON
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & containerJSON ) , checker . IsNil )
2015-12-18 13:36:17 -05:00
c . Assert ( containerJSON . HostConfig . NetworkMode , checker . Equals , containertypes . NetworkMode ( networkMode ) , check . Commentf ( "Mismatched NetworkMode" ) )
2015-04-22 07:03:57 -04:00
}
2015-05-15 17:00:54 -04:00
func ( s * DockerSuite ) TestContainerApiCreateWithCpuSharesCpuset ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. The CpuShares part could be ported.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-15 17:00:54 -04:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"CpuShares" : 512 ,
2015-11-15 17:00:39 -05:00
"CpusetCpus" : "0" ,
2015-05-15 17:00:54 -04:00
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-05-15 17:00:54 -04:00
var container types . ContainerCreateResponse
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & container ) , checker . IsNil )
2015-05-15 17:00:54 -04:00
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-05-15 17:00:54 -04:00
2015-07-22 08:59:24 -04:00
var containerJSON types . ContainerJSON
2015-05-15 17:00:54 -04:00
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & containerJSON ) , checker . IsNil )
2015-05-15 17:00:54 -04:00
2016-01-28 09:19:25 -05:00
out := inspectField ( c , containerJSON . ID , "HostConfig.CpuShares" )
2015-11-18 19:37:42 -05:00
c . Assert ( out , checker . Equals , "512" )
2015-05-15 17:00:54 -04:00
2016-01-28 09:19:25 -05:00
outCpuset := inspectField ( c , containerJSON . ID , "HostConfig.CpusetCpus" )
2015-11-18 19:37:42 -05:00
c . Assert ( outCpuset , checker . Equals , "0" )
2015-05-15 17:00:54 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiVerifyHeader ( c * check . C ) {
2015-04-14 21:55:04 -04:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
}
2015-04-27 12:33:08 -04:00
create := func ( ct string ) ( * http . Response , io . ReadCloser , error ) {
2015-04-14 21:55:04 -04:00
jsonData := bytes . NewBuffer ( nil )
2015-11-18 19:37:42 -05:00
c . Assert ( json . NewEncoder ( jsonData ) . Encode ( config ) , checker . IsNil )
2015-04-14 21:55:04 -04:00
return sockRequestRaw ( "POST" , "/containers/create" , jsonData , ct )
}
// Try with no content-type
2015-04-27 12:33:08 -04:00
res , body , err := create ( "" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusInternalServerError )
2015-04-14 21:55:04 -04:00
body . Close ( )
2015-04-20 17:03:56 -04:00
2015-04-14 21:55:04 -04:00
// Try with wrong content-type
2015-04-27 12:33:08 -04:00
res , body , err = create ( "application/xml" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusInternalServerError )
2015-04-14 21:55:04 -04:00
body . Close ( )
// now application/json
2015-04-27 12:33:08 -04:00
res , body , err = create ( "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusCreated )
2015-04-14 21:55:04 -04:00
body . Close ( )
}
2015-04-14 22:07:04 -04:00
2015-06-28 06:16:24 -04:00
//Issue 14230. daemon should return 500 for invalid port syntax
func ( s * DockerSuite ) TestContainerApiInvalidPortSyntax ( c * check . C ) {
config := ` {
"Image" : "busybox" ,
"HostConfig" : {
2016-01-23 14:04:57 -05:00
"NetworkMode" : "default" ,
2015-06-28 06:16:24 -04:00
"PortBindings" : {
"19039;1230" : [
{ }
]
}
}
} `
res , body , err := sockRequestRaw ( "POST" , "/containers/create" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusInternalServerError )
2015-06-28 06:16:24 -04:00
b , err := readBody ( body )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( string ( b [ : ] ) , checker . Contains , "Invalid port" )
2015-06-28 06:16:24 -04:00
}
2015-04-14 22:07:04 -04:00
// Issue 7941 - test to make sure a "null" in JSON is just ignored.
// W/o this fix a null in JSON would be parsed into a string var as "null"
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestContainerApiPostCreateNull ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. Bit of this with alternate fields checked
// can probably be ported.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-14 22:07:04 -04:00
config := ` {
"Hostname" : "" ,
"Domainname" : "" ,
"Memory" : 0 ,
"MemorySwap" : 0 ,
"CpuShares" : 0 ,
"Cpuset" : null ,
"AttachStdin" : true ,
"AttachStdout" : true ,
"AttachStderr" : true ,
"ExposedPorts" : { } ,
"Tty" : true ,
"OpenStdin" : true ,
"StdinOnce" : true ,
"Env" : [ ] ,
"Cmd" : "ls" ,
"Image" : "busybox" ,
"Volumes" : { } ,
"WorkingDir" : "" ,
"Entrypoint" : null ,
"NetworkDisabled" : false ,
"OnBuild" : null } `
2015-04-27 12:33:08 -04:00
res , body , err := sockRequestRaw ( "POST" , "/containers/create" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusCreated )
2015-04-14 22:07:04 -04:00
b , err := readBody ( body )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-14 22:07:04 -04:00
type createResp struct {
2015-07-22 08:59:24 -04:00
ID string
2015-04-14 22:07:04 -04:00
}
var container createResp
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( b , & container ) , checker . IsNil )
2016-01-28 09:19:25 -05:00
out := inspectField ( c , container . ID , "HostConfig.CpusetCpus" )
2015-11-18 19:37:42 -05:00
c . Assert ( out , checker . Equals , "" )
2015-05-12 02:30:16 -04:00
2016-01-28 09:19:25 -05:00
outMemory := inspectField ( c , container . ID , "HostConfig.Memory" )
2015-11-18 19:37:42 -05:00
c . Assert ( outMemory , checker . Equals , "0" )
2016-01-28 09:19:25 -05:00
outMemorySwap := inspectField ( c , container . ID , "HostConfig.MemorySwap" )
2015-11-18 19:37:42 -05:00
c . Assert ( outMemorySwap , checker . Equals , "0" )
2015-04-14 22:07:04 -04:00
}
2015-04-15 18:43:18 -04:00
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestCreateWithTooLowMemoryLimit ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Port once memory is supported
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-15 18:43:18 -04:00
config := ` {
"Image" : "busybox" ,
"Cmd" : "ls" ,
"OpenStdin" : true ,
"CpuShares" : 100 ,
"Memory" : 524287
} `
2015-07-13 08:49:08 -04:00
res , body , err := sockRequestRaw ( "POST" , "/containers/create" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-15 18:43:18 -04:00
b , err2 := readBody ( body )
2015-11-18 19:37:42 -05:00
c . Assert ( err2 , checker . IsNil )
2015-04-15 18:43:18 -04:00
2015-11-18 19:37:42 -05:00
c . Assert ( res . StatusCode , checker . Equals , http . StatusInternalServerError )
c . Assert ( string ( b ) , checker . Contains , "Minimum memory limit allowed is 4MB" )
2015-04-15 18:43:18 -04:00
}
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestStartWithTooLowMemoryLimit ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Port once memory is supported
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "create" , "busybox" )
2015-04-15 18:43:18 -04:00
containerID := strings . TrimSpace ( out )
config := ` {
"CpuShares" : 100 ,
"Memory" : 524287
} `
2015-07-13 08:49:08 -04:00
res , body , err := sockRequestRaw ( "POST" , "/containers/" + containerID + "/start" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-15 18:43:18 -04:00
b , err2 := readBody ( body )
2015-11-18 19:37:42 -05:00
c . Assert ( err2 , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusInternalServerError )
c . Assert ( string ( b ) , checker . Contains , "Minimum memory limit allowed is 4MB" )
2015-04-15 18:43:18 -04:00
}
2015-04-24 07:57:04 -04:00
func ( s * DockerSuite ) TestContainerApiRename ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Enable for TP5. Fails on TP4.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "run" , "--name" , "TestContainerApiRename" , "-d" , "busybox" , "sh" )
2015-04-24 07:57:04 -04:00
containerID := strings . TrimSpace ( out )
2015-04-26 12:50:25 -04:00
newName := "TestContainerApiRenameNew"
2015-04-24 07:57:04 -04:00
statusCode , _ , err := sockRequest ( "POST" , "/containers/" + containerID + "/rename?name=" + newName , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-24 07:57:04 -04:00
// 204 No Content is expected, not 200
2015-11-18 19:37:42 -05:00
c . Assert ( statusCode , checker . Equals , http . StatusNoContent )
2015-04-24 07:57:04 -04:00
2016-01-28 09:19:25 -05:00
name := inspectField ( c , containerID , "Name" )
2015-11-18 19:37:42 -05:00
c . Assert ( name , checker . Equals , "/" + newName , check . Commentf ( "Failed to rename container" ) )
2015-04-24 07:57:04 -04:00
}
2015-04-29 07:56:45 -04:00
func ( s * DockerSuite ) TestContainerApiKill ( c * check . C ) {
name := "test-api-kill"
2016-01-26 23:16:36 -05:00
runSleepingContainer ( c , "-i" , "--name" , name )
2015-04-29 07:56:45 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/" + name + "/kill" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-04-29 07:56:45 -04:00
2016-01-28 09:19:25 -05:00
state := inspectField ( c , name , "State.Running" )
2015-11-18 19:37:42 -05:00
c . Assert ( state , checker . Equals , "false" , check . Commentf ( "got wrong State from container %s: %q" , name , state ) )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiRestart ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. This is flaky due to the timing
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-29 07:56:45 -04:00
name := "test-api-restart"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "-di" , "--name" , name , "busybox" , "top" )
2015-04-29 07:56:45 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/" + name + "/restart?t=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
c . Assert ( waitInspect ( name , "{{ .State.Restarting }} {{ .State.Running }}" , "false true" , 5 * time . Second ) , checker . IsNil )
2015-04-29 07:56:45 -04:00
}
2015-05-06 19:49:16 -04:00
func ( s * DockerSuite ) TestContainerApiRestartNotimeoutParam ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. This is flaky due to the timing
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-06 19:49:16 -04:00
name := "test-api-restart-no-timeout-param"
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "run" , "-di" , "--name" , name , "busybox" , "top" )
2015-05-06 19:49:16 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-06 19:49:16 -04:00
status , _ , err := sockRequest ( "POST" , "/containers/" + name + "/restart" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
c . Assert ( waitInspect ( name , "{{ .State.Restarting }} {{ .State.Running }}" , "false true" , 5 * time . Second ) , checker . IsNil )
2015-05-06 19:49:16 -04:00
}
2015-04-29 07:56:45 -04:00
func ( s * DockerSuite ) TestContainerApiStart ( c * check . C ) {
name := "testing-start"
config := map [ string ] interface { } {
"Image" : "busybox" ,
2016-01-26 23:16:36 -05:00
"Cmd" : append ( [ ] string { "/bin/sh" , "-c" } , defaultSleepCommand ... ) ,
2015-04-29 07:56:45 -04:00
"OpenStdin" : true ,
}
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-04-29 07:56:45 -04:00
conf := make ( map [ string ] interface { } )
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , conf )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-04-29 07:56:45 -04:00
// second call to start should give 304
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , conf )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2016-02-24 17:59:11 -05:00
// TODO(tibor): figure out why this doesn't work on windows
if isLocalDaemon {
c . Assert ( status , checker . Equals , http . StatusNotModified )
}
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiStop ( c * check . C ) {
name := "test-api-stop"
2016-01-26 23:16:36 -05:00
runSleepingContainer ( c , "-i" , "--name" , name )
2015-04-29 07:56:45 -04:00
2016-01-23 14:04:57 -05:00
status , _ , err := sockRequest ( "POST" , "/containers/" + name + "/stop?t=30" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2016-01-23 14:04:57 -05:00
c . Assert ( waitInspect ( name , "{{ .State.Running }}" , "false" , 60 * time . Second ) , checker . IsNil )
2015-04-29 07:56:45 -04:00
// second call to start should give 304
2016-01-23 14:04:57 -05:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/stop?t=30" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNotModified )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiWait ( c * check . C ) {
name := "test-api-wait"
2016-01-26 23:16:36 -05:00
sleepCmd := "/bin/sleep"
if daemonPlatform == "windows" {
sleepCmd = "sleep"
}
2016-01-23 14:04:57 -05:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , sleepCmd , "5" )
2015-04-29 07:56:45 -04:00
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/wait" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2016-01-23 14:04:57 -05:00
c . Assert ( waitInspect ( name , "{{ .State.Running }}" , "false" , 60 * time . Second ) , checker . IsNil )
2015-04-29 07:56:45 -04:00
var waitres types . ContainerWaitResponse
2015-11-18 19:37:42 -05:00
c . Assert ( json . Unmarshal ( body , & waitres ) , checker . IsNil )
c . Assert ( waitres . StatusCode , checker . Equals , 0 )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiCopy ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. This can be ported.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-29 07:56:45 -04:00
name := "test-container-api-copy"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "touch" , "/test.txt" )
2015-04-29 07:56:45 -04:00
postData := types . CopyConfig {
Resource : "/test.txt" ,
}
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/copy" , postData )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
2015-04-29 07:56:45 -04:00
found := false
for tarReader := tar . NewReader ( bytes . NewReader ( body ) ) ; ; {
h , err := tarReader . Next ( )
if err != nil {
if err == io . EOF {
break
}
c . Fatal ( err )
}
if h . Name == "test.txt" {
found = true
break
}
}
2015-11-18 19:37:42 -05:00
c . Assert ( found , checker . True )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiCopyResourcePathEmpty ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. This can be ported.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-29 07:56:45 -04:00
name := "test-container-api-copy-resource-empty"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "touch" , "/test.txt" )
2015-04-29 07:56:45 -04:00
postData := types . CopyConfig {
Resource : "" ,
}
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/copy" , postData )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
c . Assert ( string ( body ) , checker . Matches , "Path cannot be empty\n" )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiCopyResourcePathNotFound ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows to Windows CI. This can be ported.
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-29 07:56:45 -04:00
name := "test-container-api-copy-resource-not-found"
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "run" , "--name" , name , "busybox" )
2015-04-29 07:56:45 -04:00
postData := types . CopyConfig {
Resource : "/notexist" ,
}
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/copy" , postData )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
c . Assert ( string ( body ) , checker . Matches , "Could not find the file /notexist in container " + name + "\n" )
2015-04-29 07:56:45 -04:00
}
func ( s * DockerSuite ) TestContainerApiCopyContainerNotFound ( c * check . C ) {
postData := types . CopyConfig {
Resource : "/something" ,
}
status , _ , err := sockRequest ( "POST" , "/containers/notexists/copy" , postData )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNotFound )
2015-04-29 07:56:45 -04:00
}
2015-05-03 08:54:55 -04:00
func ( s * DockerSuite ) TestContainerApiDelete ( c * check . C ) {
2016-01-26 23:16:36 -05:00
out , _ := runSleepingContainer ( c )
2015-05-03 08:54:55 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
2015-07-14 02:35:36 -04:00
dockerCmd ( c , "stop" , id )
2015-05-03 08:54:55 -04:00
status , _ , err := sockRequest ( "DELETE" , "/containers/" + id , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-05-03 08:54:55 -04:00
}
func ( s * DockerSuite ) TestContainerApiDeleteNotExist ( c * check . C ) {
status , body , err := sockRequest ( "DELETE" , "/containers/doesnotexist" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNotFound )
2015-12-04 02:00:08 -05:00
c . Assert ( string ( body ) , checker . Matches , "No such container: doesnotexist\n" )
2015-05-03 08:54:55 -04:00
}
func ( s * DockerSuite ) TestContainerApiDeleteForce ( c * check . C ) {
2016-01-26 23:16:36 -05:00
out , _ := runSleepingContainer ( c )
2015-05-03 08:54:55 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
status , _ , err := sockRequest ( "DELETE" , "/containers/" + id + "?force=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
2015-05-03 08:54:55 -04:00
}
func ( s * DockerSuite ) TestContainerApiDeleteRemoveLinks ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows does not support links
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-14 02:35:36 -04:00
out , _ := dockerCmd ( c , "run" , "-d" , "--name" , "tlink1" , "busybox" , "top" )
2015-05-03 08:54:55 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
2015-07-14 02:35:36 -04:00
out , _ = dockerCmd ( c , "run" , "--link" , "tlink1:tlink1" , "--name" , "tlink2" , "-d" , "busybox" , "top" )
2015-05-03 08:54:55 -04:00
id2 := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id2 ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
2016-01-28 09:19:25 -05:00
links := inspectFieldJSON ( c , id2 , "HostConfig.Links" )
2015-11-18 19:37:42 -05:00
c . Assert ( links , checker . Equals , "[\"/tlink1:/tlink2/tlink1\"]" , check . Commentf ( "expected to have links between containers" ) )
2015-05-03 08:54:55 -04:00
2015-09-03 20:51:04 -04:00
status , b , err := sockRequest ( "DELETE" , "/containers/tlink2/tlink1?link=1" , nil )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusNoContent , check . Commentf ( string ( b ) ) )
2015-05-03 08:54:55 -04:00
2016-01-28 09:19:25 -05:00
linksPostRm := inspectFieldJSON ( c , id2 , "HostConfig.Links" )
2015-11-18 19:37:42 -05:00
c . Assert ( linksPostRm , checker . Equals , "null" , check . Commentf ( "call to api deleteContainer links should have removed the specified links" ) )
2015-05-03 08:54:55 -04:00
}
func ( s * DockerSuite ) TestContainerApiDeleteConflict ( c * check . C ) {
2016-01-26 23:16:36 -05:00
out , _ := runSleepingContainer ( c )
2015-05-03 08:54:55 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
status , _ , err := sockRequest ( "DELETE" , "/containers/" + id , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusConflict )
2015-05-03 08:54:55 -04:00
}
func ( s * DockerSuite ) TestContainerApiDeleteRemoveVolume ( c * check . C ) {
testRequires ( c , SameHostDaemon )
2016-01-23 14:04:57 -05:00
vol := "/testvolume"
if daemonPlatform == "windows" {
vol = ` c:\testvolume `
}
2016-01-26 23:16:36 -05:00
out , _ := runSleepingContainer ( c , "-v" , vol )
2015-05-03 08:54:55 -04:00
id := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( id ) , checker . IsNil )
2015-05-03 08:54:55 -04:00
2016-01-23 14:04:57 -05:00
source , err := inspectMountSourceField ( id , vol )
2015-06-03 15:21:38 -04:00
_ , err = os . Stat ( source )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-05-03 08:54:55 -04:00
status , _ , err := sockRequest ( "DELETE" , "/containers/" + id + "?v=1&force=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusNoContent )
_ , err = os . Stat ( source )
c . Assert ( os . IsNotExist ( err ) , checker . True , check . Commentf ( "expected to get ErrNotExist error, got %v" , err ) )
2015-05-03 08:54:55 -04:00
}
2015-04-29 13:48:30 -04:00
// Regression test for https://github.com/docker/docker/issues/6231
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestContainerApiChunkedEncoding ( c * check . C ) {
// TODO Windows CI: This can be ported
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-04-29 13:48:30 -04:00
out , _ := dockerCmd ( c , "create" , "-v" , "/foo" , "busybox" , "true" )
id := strings . TrimSpace ( out )
conn , err := sockConn ( time . Duration ( 10 * time . Second ) )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-29 13:48:30 -04:00
client := httputil . NewClientConn ( conn , nil )
defer client . Close ( )
bindCfg := strings . NewReader ( ` { "Binds": ["/tmp:/foo"]} ` )
req , err := http . NewRequest ( "POST" , "/containers/" + id + "/start" , bindCfg )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-29 13:48:30 -04:00
req . Header . Set ( "Content-Type" , "application/json" )
// This is a cheat to make the http request do chunked encoding
// Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
// https://golang.org/src/pkg/net/http/request.go?s=11980:12172
req . ContentLength = - 1
resp , err := client . Do ( req )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil , check . Commentf ( "error starting container with chunked encoding" ) )
2015-04-29 13:48:30 -04:00
resp . Body . Close ( )
2015-11-18 19:37:42 -05:00
c . Assert ( resp . StatusCode , checker . Equals , 204 )
2015-04-29 13:48:30 -04:00
2016-01-28 09:19:25 -05:00
out = inspectFieldJSON ( c , id , "HostConfig.Binds" )
2015-04-29 13:48:30 -04:00
var binds [ ] string
2015-11-18 19:37:42 -05:00
c . Assert ( json . NewDecoder ( strings . NewReader ( out ) ) . Decode ( & binds ) , checker . IsNil )
c . Assert ( binds , checker . HasLen , 1 , check . Commentf ( "Got unexpected binds: %v" , binds ) )
2015-04-29 13:48:30 -04:00
expected := "/tmp:/foo"
2015-11-18 19:37:42 -05:00
c . Assert ( binds [ 0 ] , checker . Equals , expected , check . Commentf ( "got incorrect bind spec" ) )
2015-04-29 13:48:30 -04:00
}
2015-04-27 14:55:11 -04:00
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestContainerApiPostContainerStop ( c * check . C ) {
2016-01-26 23:16:36 -05:00
out , _ := runSleepingContainer ( c )
2015-04-27 14:55:11 -04:00
containerID := strings . TrimSpace ( out )
2015-11-18 19:37:42 -05:00
c . Assert ( waitRun ( containerID ) , checker . IsNil )
2015-04-27 14:55:11 -04:00
statusCode , _ , err := sockRequest ( "POST" , "/containers/" + containerID + "/stop" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-04-27 14:55:11 -04:00
// 204 No Content is expected, not 200
2015-11-18 19:37:42 -05:00
c . Assert ( statusCode , checker . Equals , http . StatusNoContent )
c . Assert ( waitInspect ( containerID , "{{ .State.Running }}" , "false" , 5 * time . Second ) , checker . IsNil )
2015-04-27 14:55:11 -04:00
}
2015-06-26 01:15:57 -04:00
// #14170
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestPostContainerApiCreateWithStringOrSliceEntrypoint ( c * check . C ) {
2015-06-26 01:15:57 -04:00
config := struct {
Image string
Entrypoint string
Cmd [ ] string
} { "busybox" , "echo" , [ ] string { "hello" , "world" } }
_ , _ , err := sockRequest ( "POST" , "/containers/create?name=echotest" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-26 01:15:57 -04:00
out , _ := dockerCmd ( c , "start" , "-a" , "echotest" )
2015-11-18 19:37:42 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "hello world" )
2015-06-26 01:15:57 -04:00
config2 := struct {
Image string
Entrypoint [ ] string
Cmd [ ] string
} { "busybox" , [ ] string { "echo" } , [ ] string { "hello" , "world" } }
_ , _ , err = sockRequest ( "POST" , "/containers/create?name=echotest2" , config2 )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-26 01:15:57 -04:00
out , _ = dockerCmd ( c , "start" , "-a" , "echotest2" )
2015-11-18 19:37:42 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "hello world" )
2015-06-26 01:15:57 -04:00
}
// #14170
func ( s * DockerSuite ) TestPostContainersCreateWithStringOrSliceCmd ( c * check . C ) {
config := struct {
Image string
Entrypoint string
Cmd string
} { "busybox" , "echo" , "hello world" }
_ , _ , err := sockRequest ( "POST" , "/containers/create?name=echotest" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-26 01:15:57 -04:00
out , _ := dockerCmd ( c , "start" , "-a" , "echotest" )
2015-11-18 19:37:42 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "hello world" )
2015-06-26 01:15:57 -04:00
config2 := struct {
Image string
Cmd [ ] string
} { "busybox" , [ ] string { "echo" , "hello" , "world" } }
_ , _ , err = sockRequest ( "POST" , "/containers/create?name=echotest2" , config2 )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-06-26 01:15:57 -04:00
out , _ = dockerCmd ( c , "start" , "-a" , "echotest2" )
2015-11-18 19:37:42 -05:00
c . Assert ( strings . TrimSpace ( out ) , checker . Equals , "hello world" )
2015-06-26 01:15:57 -04:00
}
2015-07-01 13:59:18 -04:00
// regression #14318
func ( s * DockerSuite ) TestPostContainersCreateWithStringOrSliceCapAddDrop ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows doesn't support CapAdd/CapDrop
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-01 13:59:18 -04:00
config := struct {
Image string
CapAdd string
CapDrop string
} { "busybox" , "NET_ADMIN" , "SYS_ADMIN" }
status , _ , err := sockRequest ( "POST" , "/containers/create?name=capaddtest0" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-07-01 13:59:18 -04:00
config2 := struct {
Image string
CapAdd [ ] string
CapDrop [ ] string
} { "busybox" , [ ] string { "NET_ADMIN" , "SYS_ADMIN" } , [ ] string { "SETGID" } }
status , _ , err = sockRequest ( "POST" , "/containers/create?name=capaddtest1" , config2 )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-07-01 13:59:18 -04:00
}
2015-07-21 15:18:56 -04:00
// #14640
func ( s * DockerSuite ) TestPostContainersStartWithoutLinksInHostConfig ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Windows doesn't support supplying a hostconfig on start.
// An alternate test could be written to validate the negative testing aspect of this
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-21 15:18:56 -04:00
name := "test-host-config-links"
2016-01-26 23:16:36 -05:00
dockerCmd ( c , append ( [ ] string { "create" , "--name" , name , "busybox" } , defaultSleepCommand ... ) ... )
2015-07-21 15:18:56 -04:00
2016-01-28 09:19:25 -05:00
hc := inspectFieldJSON ( c , name , "HostConfig" )
2015-07-21 15:18:56 -04:00
config := ` { "HostConfig": ` + hc + ` } `
2015-07-23 07:24:14 -04:00
res , b , err := sockRequestRaw ( "POST" , "/containers/" + name + "/start" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusNoContent )
2015-07-23 07:24:14 -04:00
b . Close ( )
2015-07-21 15:18:56 -04:00
}
// #14640
func ( s * DockerSuite ) TestPostContainersStartWithLinksInHostConfig ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Windows doesn't support supplying a hostconfig on start.
// An alternate test could be written to validate the negative testing aspect of this
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-21 15:18:56 -04:00
name := "test-host-config-links"
dockerCmd ( c , "run" , "--name" , "foo" , "-d" , "busybox" , "top" )
dockerCmd ( c , "create" , "--name" , name , "--link" , "foo:bar" , "busybox" , "top" )
2016-01-28 09:19:25 -05:00
hc := inspectFieldJSON ( c , name , "HostConfig" )
2015-07-21 15:18:56 -04:00
config := ` { "HostConfig": ` + hc + ` } `
2015-07-23 07:24:14 -04:00
res , b , err := sockRequestRaw ( "POST" , "/containers/" + name + "/start" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusNoContent )
2015-07-23 07:24:14 -04:00
b . Close ( )
2015-07-21 15:18:56 -04:00
}
// #14640
func ( s * DockerSuite ) TestPostContainersStartWithLinksInHostConfigIdLinked ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows does not support links
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-07-21 15:18:56 -04:00
name := "test-host-config-links"
out , _ := dockerCmd ( c , "run" , "--name" , "link0" , "-d" , "busybox" , "top" )
id := strings . TrimSpace ( out )
dockerCmd ( c , "create" , "--name" , name , "--link" , id , "busybox" , "top" )
2016-01-28 09:19:25 -05:00
hc := inspectFieldJSON ( c , name , "HostConfig" )
2015-07-21 15:18:56 -04:00
config := ` { "HostConfig": ` + hc + ` } `
2015-07-23 07:24:14 -04:00
res , b , err := sockRequestRaw ( "POST" , "/containers/" + name + "/start" , strings . NewReader ( config ) , "application/json" )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusNoContent )
2015-07-23 07:24:14 -04:00
b . Close ( )
2015-07-21 15:18:56 -04:00
}
2015-07-25 07:39:13 -04:00
// #14915
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestContainerApiCreateNoHostConfig118 ( c * check . C ) {
2015-07-25 07:39:13 -04:00
config := struct {
Image string
} { "busybox" }
status , _ , err := sockRequest ( "POST" , "/v1.18/containers/create" , config )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusCreated )
2015-07-25 07:39:13 -04:00
}
2015-07-24 17:12:55 -04:00
// Ensure an error occurs when you have a container read-only rootfs but you
// extract an archive to a symlink in a writable volume which points to a
// directory outside of the volume.
func ( s * DockerSuite ) TestPutContainerArchiveErrSymlinkInVolumeToReadOnlyRootfs ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Windows does not support read-only rootfs
2015-09-18 13:41:12 -04:00
// Requires local volume mount bind.
// --read-only + userns has remount issues
2016-01-08 16:49:43 -05:00
testRequires ( c , SameHostDaemon , NotUserNamespace , DaemonIsLinux )
2015-07-24 17:12:55 -04:00
testVol := getTestDir ( c , "test-put-container-archive-err-symlink-in-volume-to-read-only-rootfs-" )
defer os . RemoveAll ( testVol )
makeTestContentInDir ( c , testVol )
cID := makeTestContainer ( c , testContainerOptions {
readOnly : true ,
volumes : defaultVolumes ( testVol ) , // Our bind mount is at /vol2
} )
defer deleteContainer ( cID )
// Attempt to extract to a symlink in the volume which points to a
// directory outside the volume. This should cause an error because the
// rootfs is read-only.
query := make ( url . Values , 1 )
query . Set ( "path" , "/vol2/symlinkToAbsDir" )
urlPath := fmt . Sprintf ( "/v1.20/containers/%s/archive?%s" , cID , query . Encode ( ) )
statusCode , body , err := sockRequest ( "PUT" , urlPath , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
2015-07-24 17:12:55 -04:00
if ! isCpCannotCopyReadOnly ( fmt . Errorf ( string ( body ) ) ) {
c . Fatalf ( "expected ErrContainerRootfsReadonly error, but got %d: %s" , statusCode , string ( body ) )
}
}
2015-09-18 12:39:14 -04:00
2016-01-23 14:04:57 -05:00
func ( s * DockerSuite ) TestContainerApiGetContainersJSONEmpty ( c * check . C ) {
2015-09-18 12:39:14 -04:00
status , body , err := sockRequest ( "GET" , "/containers/json?all=1" , nil )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusOK )
c . Assert ( string ( body ) , checker . Equals , "[]\n" )
2015-09-18 12:39:14 -04:00
}
2015-09-08 14:40:55 -04:00
func ( s * DockerSuite ) TestPostContainersCreateWithWrongCpusetValues ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Not supported on Windows
2015-09-08 14:40:55 -04:00
testRequires ( c , DaemonIsLinux )
c1 := struct {
Image string
CpusetCpus string
} { "busybox" , "1-42,," }
name := "wrong-cpuset-cpus"
status , body , err := sockRequest ( "POST" , "/containers/create?name=" + name , c1 )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
2015-09-08 14:40:55 -04:00
expected := "Invalid value 1-42,, for cpuset cpus.\n"
2015-11-18 19:37:42 -05:00
c . Assert ( string ( body ) , checker . Equals , expected )
2015-09-08 14:40:55 -04:00
c2 := struct {
Image string
CpusetMems string
} { "busybox" , "42-3,1--" }
name = "wrong-cpuset-mems"
status , body , err = sockRequest ( "POST" , "/containers/create?name=" + name , c2 )
2015-11-18 19:37:42 -05:00
c . Assert ( err , checker . IsNil )
c . Assert ( status , checker . Equals , http . StatusInternalServerError )
2015-09-08 14:40:55 -04:00
expected = "Invalid value 42-3,1-- for cpuset mems.\n"
2015-11-18 19:37:42 -05:00
c . Assert ( string ( body ) , checker . Equals , expected )
2015-09-08 14:40:55 -04:00
}
2015-11-30 17:44:34 -05:00
func ( s * DockerSuite ) TestStartWithNilDNS ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// TODO Windows: Add once DNS is supported
2015-11-30 17:44:34 -05:00
testRequires ( c , DaemonIsLinux )
out , _ := dockerCmd ( c , "create" , "busybox" )
containerID := strings . TrimSpace ( out )
config := ` { "HostConfig": { "Dns": null}} `
res , b , err := sockRequestRaw ( "POST" , "/containers/" + containerID + "/start" , strings . NewReader ( config ) , "application/json" )
c . Assert ( err , checker . IsNil )
c . Assert ( res . StatusCode , checker . Equals , http . StatusNoContent )
b . Close ( )
2016-01-28 09:19:25 -05:00
dns := inspectFieldJSON ( c , containerID , "HostConfig.Dns" )
2015-11-30 17:44:34 -05:00
c . Assert ( dns , checker . Equals , "[]" )
}
2015-11-26 07:14:09 -05:00
func ( s * DockerSuite ) TestPostContainersCreateShmSizeNegative ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// ShmSize is not supported on Windows
2016-01-08 16:49:43 -05:00
testRequires ( c , DaemonIsLinux )
2015-11-26 07:14:09 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"HostConfig" : map [ string ] interface { } { "ShmSize" : - 1 } ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( string ( body ) , checker . Contains , "SHM size must be greater then 0" )
}
func ( s * DockerSuite ) TestPostContainersCreateShmSizeHostConfigOmitted ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// ShmSize is not supported on Windows
2016-01-08 16:49:43 -05:00
testRequires ( c , DaemonIsLinux )
2015-12-02 15:43:51 -05:00
var defaultSHMSize int64 = 67108864
2015-11-26 07:14:09 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Cmd" : "mount" ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusCreated )
var container types . ContainerCreateResponse
c . Assert ( json . Unmarshal ( body , & container ) , check . IsNil )
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusOK )
var containerJSON types . ContainerJSON
c . Assert ( json . Unmarshal ( body , & containerJSON ) , check . IsNil )
2015-12-29 15:49:17 -05:00
c . Assert ( containerJSON . HostConfig . ShmSize , check . Equals , defaultSHMSize )
2015-11-26 07:14:09 -05:00
out , _ := dockerCmd ( c , "start" , "-i" , containerJSON . ID )
shmRegexp := regexp . MustCompile ( ` shm on /dev/shm type tmpfs(.*)size=65536k ` )
if ! shmRegexp . MatchString ( out ) {
c . Fatalf ( "Expected shm of 64MB in mount command, got %v" , out )
}
}
func ( s * DockerSuite ) TestPostContainersCreateShmSizeOmitted ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// ShmSize is not supported on Windows
2016-01-08 16:49:43 -05:00
testRequires ( c , DaemonIsLinux )
2015-11-26 07:14:09 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"HostConfig" : map [ string ] interface { } { } ,
"Cmd" : "mount" ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusCreated )
var container types . ContainerCreateResponse
c . Assert ( json . Unmarshal ( body , & container ) , check . IsNil )
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusOK )
var containerJSON types . ContainerJSON
c . Assert ( json . Unmarshal ( body , & containerJSON ) , check . IsNil )
2015-12-29 15:49:17 -05:00
c . Assert ( containerJSON . HostConfig . ShmSize , check . Equals , int64 ( 67108864 ) )
2015-11-26 07:14:09 -05:00
out , _ := dockerCmd ( c , "start" , "-i" , containerJSON . ID )
shmRegexp := regexp . MustCompile ( ` shm on /dev/shm type tmpfs(.*)size=65536k ` )
if ! shmRegexp . MatchString ( out ) {
c . Fatalf ( "Expected shm of 64MB in mount command, got %v" , out )
}
}
func ( s * DockerSuite ) TestPostContainersCreateWithShmSize ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// ShmSize is not supported on Windows
2016-01-08 16:49:43 -05:00
testRequires ( c , DaemonIsLinux )
2015-11-26 07:14:09 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Cmd" : "mount" ,
"HostConfig" : map [ string ] interface { } { "ShmSize" : 1073741824 } ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusCreated )
var container types . ContainerCreateResponse
c . Assert ( json . Unmarshal ( body , & container ) , check . IsNil )
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusOK )
var containerJSON types . ContainerJSON
c . Assert ( json . Unmarshal ( body , & containerJSON ) , check . IsNil )
2015-12-29 15:49:17 -05:00
c . Assert ( containerJSON . HostConfig . ShmSize , check . Equals , int64 ( 1073741824 ) )
2015-11-26 07:14:09 -05:00
out , _ := dockerCmd ( c , "start" , "-i" , containerJSON . ID )
shmRegex := regexp . MustCompile ( ` shm on /dev/shm type tmpfs(.*)size=1048576k ` )
if ! shmRegex . MatchString ( out ) {
c . Fatalf ( "Expected shm of 1GB in mount command, got %v" , out )
}
}
func ( s * DockerSuite ) TestPostContainersCreateMemorySwappinessHostConfigOmitted ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// Swappiness is not supported on Windows
2016-01-08 16:49:43 -05:00
testRequires ( c , DaemonIsLinux )
2015-11-26 07:14:09 -05:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
}
status , body , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusCreated )
var container types . ContainerCreateResponse
c . Assert ( json . Unmarshal ( body , & container ) , check . IsNil )
status , body , err = sockRequest ( "GET" , "/containers/" + container . ID + "/json" , nil )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusOK )
var containerJSON types . ContainerJSON
c . Assert ( json . Unmarshal ( body , & containerJSON ) , check . IsNil )
2015-12-01 21:53:52 -05:00
c . Assert ( * containerJSON . HostConfig . MemorySwappiness , check . Equals , int64 ( - 1 ) )
2015-11-26 07:14:09 -05:00
}
2015-10-13 05:26:27 -04:00
// check validation is done daemon side and not only in cli
func ( s * DockerSuite ) TestPostContainersCreateWithOomScoreAdjInvalidRange ( c * check . C ) {
2016-01-23 14:04:57 -05:00
// OomScoreAdj is not supported on Windows
2015-10-13 05:26:27 -04:00
testRequires ( c , DaemonIsLinux )
config := struct {
Image string
OomScoreAdj int
} { "busybox" , 1001 }
name := "oomscoreadj-over"
status , b , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
expected := "Invalid value 1001, range for oom score adj is [-1000, 1000]."
if ! strings . Contains ( string ( b ) , expected ) {
c . Fatalf ( "Expected output to contain %q, got %q" , expected , string ( b ) )
}
config = struct {
Image string
OomScoreAdj int
} { "busybox" , - 1001 }
name = "oomscoreadj-low"
status , b , err = sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( err , check . IsNil )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
expected = "Invalid value -1001, range for oom score adj is [-1000, 1000]."
if ! strings . Contains ( string ( b ) , expected ) {
c . Fatalf ( "Expected output to contain %q, got %q" , expected , string ( b ) )
}
}