2014-10-14 21:32:25 +00:00
package main
import (
"bytes"
"encoding/json"
"io"
2015-04-14 08:00:46 +00:00
"net/http"
2014-10-14 21:32:25 +00:00
"os/exec"
2014-12-12 16:01:05 +00:00
"strings"
2015-01-20 00:10:26 +00:00
"time"
2015-04-11 21:49:14 +00:00
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
2015-04-18 16:46:47 +00:00
"github.com/go-check/check"
2014-10-14 21:32:25 +00:00
)
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiGetAll ( c * check . C ) {
2014-10-14 21:32:25 +00:00
startCount , err := getContainerCount ( )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Cannot query container count: %v" , err )
2014-10-14 21:32:25 +00:00
}
2014-10-21 22:48:32 +00:00
name := "getall"
runCmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "true" )
2014-10-14 21:32:25 +00:00
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Error on container creation: %v, output: %q" , err , out )
2014-10-14 21:32:25 +00:00
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequest ( "GET" , "/containers/json?all=1" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2014-10-14 21:32:25 +00:00
2014-10-21 22:48:32 +00:00
var inspectJSON [ ] struct {
Names [ ] string
}
2014-10-14 21:32:25 +00:00
if err = json . Unmarshal ( body , & inspectJSON ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "unable to unmarshal response body: %v" , err )
2014-10-14 21:32:25 +00:00
}
if len ( inspectJSON ) != startCount + 1 {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Expected %d container(s), %d found (started with: %d)" , startCount + 1 , len ( inspectJSON ) , startCount )
2014-10-14 21:32:25 +00:00
}
2014-10-21 22:48:32 +00:00
if actual := inspectJSON [ 0 ] . Names [ 0 ] ; actual != "/" + name {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Container Name mismatch. Expected: %q, received: %q\n" , "/" + name , actual )
2014-10-14 21:32:25 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiGetExport ( c * check . C ) {
2014-10-21 22:48:32 +00:00
name := "exportcontainer"
runCmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "touch" , "/test" )
2014-10-14 21:32:25 +00:00
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Error on container creation: %v, output: %q" , err , out )
2014-10-14 21:32:25 +00:00
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/export" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2014-10-14 21:32:25 +00:00
found := false
for tarReader := tar . NewReader ( bytes . NewReader ( body ) ) ; ; {
h , err := tarReader . Next ( )
if err != nil {
if err == io . EOF {
break
}
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-10-14 21:32:25 +00:00
}
if h . Name == "test" {
found = true
break
}
}
if ! found {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "The created test file has not been found in the exported image" )
2014-10-14 21:32:25 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiGetChanges ( c * check . C ) {
2014-10-21 22:48:32 +00:00
name := "changescontainer"
runCmd := exec . Command ( dockerBinary , "run" , "--name" , name , "busybox" , "rm" , "/etc/passwd" )
2014-10-14 21:32:25 +00:00
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Error on container creation: %v, output: %q" , err , out )
2014-10-14 21:32:25 +00:00
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/changes" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2014-10-14 21:32:25 +00:00
changes := [ ] struct {
Kind int
Path string
} { }
if err = json . Unmarshal ( body , & changes ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "unable to unmarshal response body: %v" , err )
2014-10-14 21:32:25 +00: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
}
}
if ! success {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "/etc/passwd has been removed but is not present in the diff" )
2014-10-14 21:32:25 +00:00
}
}
2014-12-12 16:01:05 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiStartVolumeBinds ( c * check . C ) {
2014-12-12 16:01:05 +00:00
name := "testing"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { "/tmp" : { } } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
2015-02-14 06:59:01 +00:00
bindPath := randomUnixTmpDirPath ( "test" )
2014-12-12 16:01:05 +00:00
config = map [ string ] interface { } {
"Binds" : [ ] string { bindPath + ":/tmp" } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , config )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
pth , err := inspectFieldMap ( name , "Volumes" , "/tmp" )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-12-12 16:01:05 +00:00
}
if pth != bindPath {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected volume host path to be %s, got %s" , bindPath , pth )
2014-12-12 16:01:05 +00:00
}
}
2015-02-09 16:17:41 +00:00
// Test for GH#10618
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiStartDupVolumeBinds ( c * check . C ) {
2015-02-09 16:17:41 +00:00
name := "testdups"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { "/tmp" : { } } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2015-02-09 16:17:41 +00:00
2015-02-14 06:59:01 +00:00
bindPath1 := randomUnixTmpDirPath ( "test1" )
bindPath2 := randomUnixTmpDirPath ( "test2" )
2015-02-09 16:17:41 +00:00
config = map [ string ] interface { } {
"Binds" : [ ] string { bindPath1 + ":/tmp" , bindPath2 + ":/tmp" } ,
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequest ( "POST" , "/containers/" + name + "/start" , config )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( err , check . IsNil )
if ! strings . Contains ( string ( body ) , "Duplicate volume" ) {
c . Fatalf ( "Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v" , string ( body ) , err )
2015-02-09 16:17:41 +00:00
}
}
2015-04-20 21:03:56 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiStartVolumesFrom ( c * check . C ) {
2014-12-12 16:01:05 +00:00
volName := "voltst"
volPath := "/tmp"
if out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-d" , "--name" , volName , "-v" , volPath , "busybox" ) ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( out , err )
2014-12-12 16:01:05 +00:00
}
2015-04-26 16:50:25 +00:00
name := "TestContainerApiStartDupVolumeBinds"
2014-12-12 16:01:05 +00:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { volPath : { } } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
config = map [ string ] interface { } {
"VolumesFrom" : [ ] string { volName } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , config )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
pth , err := inspectFieldMap ( name , "Volumes" , volPath )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-12-12 16:01:05 +00:00
}
pth2 , err := inspectFieldMap ( volName , "Volumes" , volPath )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-12-12 16:01:05 +00:00
}
if pth != pth2 {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected volume host path to be %s, got %s" , pth , pth2 )
2014-12-12 16:01:05 +00:00
}
}
// Ensure that volumes-from has priority over binds/anything else
// This is pretty much the same as TestRunApplyVolumesFromBeforeVolumes, except with passing the VolumesFrom and the bind on start
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestVolumesFromHasPriority ( c * check . C ) {
2015-04-02 01:06:28 +00:00
volName := "voltst2"
2014-12-12 16:01:05 +00:00
volPath := "/tmp"
if out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "run" , "-d" , "--name" , volName , "-v" , volPath , "busybox" ) ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( out , err )
2014-12-12 16:01:05 +00:00
}
name := "testing"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Volumes" : map [ string ] struct { } { volPath : { } } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/create?name=" + name , config )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
2015-02-14 06:59:01 +00:00
bindPath := randomUnixTmpDirPath ( "test" )
2014-12-12 16:01:05 +00:00
config = map [ string ] interface { } {
"VolumesFrom" : [ ] string { volName } ,
"Binds" : [ ] string { bindPath + ":/tmp" } ,
}
2015-04-20 21:03:56 +00:00
status , _ , err = sockRequest ( "POST" , "/containers/" + name + "/start" , config )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2014-12-12 16:01:05 +00:00
pth , err := inspectFieldMap ( name , "Volumes" , volPath )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-12-12 16:01:05 +00:00
}
pth2 , err := inspectFieldMap ( volName , "Volumes" , volPath )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2014-12-12 16:01:05 +00:00
}
if pth != pth2 {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected volume host path to be %s, got %s" , pth , pth2 )
2014-12-12 16:01:05 +00:00
}
}
2015-01-20 00:10:26 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestGetContainerStats ( c * check . C ) {
2015-01-21 20:14:28 +00:00
var (
name = "statscontainer"
runCmd = exec . Command ( dockerBinary , "run" , "-d" , "--name" , name , "busybox" , "top" )
)
2015-01-20 00:10:26 +00:00
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Error on container creation: %v, output: %q" , err , out )
2015-01-20 00:10:26 +00:00
}
2015-01-21 20:14:28 +00:00
type b struct {
body [ ] byte
err error
}
bc := make ( chan b , 1 )
2015-01-20 00:10:26 +00:00
go func ( ) {
2015-04-20 21:03:56 +00:00
status , body , err := sockRequest ( "GET" , "/containers/" + name + "/stats" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-01-21 20:14:28 +00:00
bc <- b { body , err }
2015-01-20 00:10:26 +00:00
} ( )
2015-01-21 20:14:28 +00:00
// allow some time to stream the stats from the container
time . Sleep ( 4 * time . Second )
if _ , err := runCommand ( exec . Command ( dockerBinary , "rm" , "-f" , name ) ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-20 00:10:26 +00:00
}
2015-01-21 20:14:28 +00: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 16:46:47 +00:00
c . Fatal ( "stream was not closed after container was removed" )
2015-01-21 20:14:28 +00:00
case sr := <- bc :
if sr . err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( sr . err )
2015-01-21 20:14:28 +00:00
}
dec := json . NewDecoder ( bytes . NewBuffer ( sr . body ) )
2015-02-24 18:47:47 +00:00
var s * types . Stats
2015-01-21 20:14:28 +00:00
// decode only one object from the stream
if err := dec . Decode ( & s ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-21 20:14:28 +00:00
}
2015-01-20 00:10:26 +00:00
}
}
2015-01-21 19:08:19 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestGetStoppedContainerStats ( c * check . C ) {
2015-03-16 11:55:34 +00:00
var (
name = "statscontainer"
runCmd = exec . Command ( dockerBinary , "create" , "--name" , name , "busybox" , "top" )
)
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Error on container creation: %v, output: %q" , err , out )
2015-03-16 11:55:34 +00:00
}
go func ( ) {
// We'll never get return for GET stats from sockRequest as of now,
// just send request and see if panic or error would happen on daemon side.
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "GET" , "/containers/" + name + "/stats" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-03-16 11:55:34 +00:00
} ( )
// allow some time to send request and let daemon deal with it
time . Sleep ( 1 * time . Second )
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiDockerfilePath ( c * check . C ) {
2015-01-21 19:08:19 +00:00
// Test to make sure we stop people from trying to leave the
// build context when specifying the path to the dockerfile
buffer := new ( bytes . Buffer )
tw := tar . NewWriter ( buffer )
defer tw . Close ( )
2015-02-02 21:17:12 +00:00
dockerfile := [ ] byte ( "FROM busybox" )
2015-01-21 19:08:19 +00:00
if err := tw . WriteHeader ( & tar . Header {
Name : "Dockerfile" ,
2015-02-02 21:17:12 +00:00
Size : int64 ( len ( dockerfile ) ) ,
2015-01-21 19:08:19 +00:00
} ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to write tar file header: %v" , err )
2015-01-21 19:08:19 +00:00
}
2015-02-02 21:17:12 +00:00
if _ , err := tw . Write ( dockerfile ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to write tar file content: %v" , err )
2015-01-21 19:08:19 +00:00
}
if err := tw . Close ( ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to close tar archive: %v" , err )
2015-01-21 19:08:19 +00:00
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build?dockerfile=../Dockerfile" , buffer , "application/x-tar" )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
out , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-01-21 19:08:19 +00:00
if ! strings . Contains ( string ( out ) , "must be within the build context" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Didn't complain about leaving build context: %s" , out )
2015-01-21 19:08:19 +00:00
}
}
2015-02-02 21:17:12 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiDockerFileRemote ( c * check . C ) {
2015-02-17 18:25:36 +00:00
server , err := fakeStorage ( map [ string ] string {
"testD" : ` FROM busybox
COPY * / tmp /
2015-03-10 12:43:49 +00:00
RUN find / - name ba *
2015-02-17 18:25:36 +00:00
RUN find / tmp / ` ,
} )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-02-17 18:25:36 +00:00
}
defer server . Close ( )
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build?dockerfile=baz&remote=" + server . URL ( ) + "/testD" , nil , "application/json" )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
buf , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-02-17 18:25:36 +00:00
2015-03-10 12:43:49 +00:00
// Make sure Dockerfile exists.
// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
2015-02-17 18:25:36 +00:00
out := string ( buf )
if ! strings . Contains ( out , "/tmp/Dockerfile" ) ||
2015-03-10 12:43:49 +00:00
strings . Contains ( out , "baz" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Incorrect output: %s" , out )
2015-02-17 18:25:36 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiLowerDockerfile ( c * check . C ) {
2015-02-17 18:25:36 +00:00
git , err := fakeGIT ( "repo" , map [ string ] string {
"dockerfile" : ` FROM busybox
RUN echo from dockerfile ` ,
2015-03-10 03:53:28 +00:00
} , false )
2015-02-17 18:25:36 +00:00
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-02-17 18:25:36 +00:00
}
defer git . Close ( )
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build?remote=" + git . RepoURL , nil , "application/json" )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
buf , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-02-17 18:25:36 +00:00
out := string ( buf )
if ! strings . Contains ( out , "from dockerfile" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Incorrect output: %s" , out )
2015-02-17 18:25:36 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiBuildGitWithF ( c * check . C ) {
2015-02-17 18:25:36 +00:00
git , err := fakeGIT ( "repo" , map [ string ] string {
"baz" : ` FROM busybox
RUN echo from baz ` ,
"Dockerfile" : ` FROM busybox
RUN echo from Dockerfile ` ,
2015-03-10 03:53:28 +00:00
} , false )
2015-02-17 18:25:36 +00:00
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-02-17 18:25:36 +00:00
}
defer git . Close ( )
// Make sure it tries to 'dockerfile' query param value
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build?dockerfile=baz&remote=" + git . RepoURL , nil , "application/json" )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
buf , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-02-17 18:25:36 +00:00
out := string ( buf )
if ! strings . Contains ( out , "from baz" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Incorrect output: %s" , out )
2015-02-17 18:25:36 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiDoubleDockerfile ( c * check . C ) {
testRequires ( c , UnixCli ) // dockerfile overwrites Dockerfile on Windows
2015-02-17 18:25:36 +00:00
git , err := fakeGIT ( "repo" , map [ string ] string {
"Dockerfile" : ` FROM busybox
RUN echo from Dockerfile ` ,
"dockerfile" : ` FROM busybox
RUN echo from dockerfile ` ,
2015-03-10 03:53:28 +00:00
} , false )
2015-02-17 18:25:36 +00:00
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-02-17 18:25:36 +00:00
}
defer git . Close ( )
// Make sure it tries to 'dockerfile' query param value
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build?remote=" + git . RepoURL , nil , "application/json" )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
buf , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-02-17 18:25:36 +00:00
out := string ( buf )
if ! strings . Contains ( out , "from Dockerfile" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Incorrect output: %s" , out )
2015-02-17 18:25:36 +00:00
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestBuildApiDockerfileSymlink ( c * check . C ) {
2015-02-02 21:17:12 +00:00
// Test to make sure we stop people from trying to leave the
// build context when specifying a symlink as the path to the dockerfile
buffer := new ( bytes . Buffer )
tw := tar . NewWriter ( buffer )
defer tw . Close ( )
if err := tw . WriteHeader ( & tar . Header {
Name : "Dockerfile" ,
Typeflag : tar . TypeSymlink ,
Linkname : "/etc/passwd" ,
} ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to write tar file header: %v" , err )
2015-02-02 21:17:12 +00:00
}
if err := tw . Close ( ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to close tar archive: %v" , err )
2015-02-02 21:17:12 +00:00
}
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/build" , buffer , "application/x-tar" )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( err , check . IsNil )
2015-04-14 02:53:54 +00:00
out , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 02:53:54 +00:00
}
2015-02-02 21:17:12 +00:00
// The reason the error is "Cannot locate specified Dockerfile" is because
// in the builder, the symlink is resolved within the context, therefore
// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
// a nonexistent file.
if ! strings . Contains ( string ( out ) , "Cannot locate specified Dockerfile: Dockerfile" ) {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "Didn't complain about leaving build context: %s" , out )
2015-02-02 21:17:12 +00:00
}
}
2015-01-26 22:31:30 +00: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 16:46:47 +00:00
func ( s * DockerSuite ) TestPostContainerBindNormalVolume ( c * check . C ) {
2015-01-26 22:31:30 +00:00
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "create" , "-v" , "/foo" , "--name=one" , "busybox" ) )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err , out )
2015-01-26 22:31:30 +00:00
}
fooDir , err := inspectFieldMap ( "one" , "Volumes" , "/foo" )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-26 22:31:30 +00:00
}
out , _ , err = runCommandWithOutput ( exec . Command ( dockerBinary , "create" , "-v" , "/foo" , "--name=two" , "busybox" ) )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err , out )
2015-01-26 22:31:30 +00:00
}
bindSpec := map [ string ] [ ] string { "Binds" : { fooDir + ":/foo" } }
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/two/start" , bindSpec )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2015-01-26 22:31:30 +00:00
fooDir2 , err := inspectFieldMap ( "two" , "Volumes" , "/foo" )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-26 22:31:30 +00:00
}
if fooDir2 != fooDir {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected volume path to be %s, got: %s" , fooDir , fooDir2 )
2015-01-26 22:31:30 +00:00
}
}
2015-04-10 01:14:01 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiPause ( c * check . C ) {
2015-04-10 01:14:01 +00:00
defer unpauseAllContainers ( )
runCmd := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "sleep" , "30" )
out , _ , err := runCommandWithOutput ( runCmd )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "failed to create a container: %s, %v" , out , err )
2015-04-10 01:14:01 +00:00
}
ContainerID := strings . TrimSpace ( out )
2015-04-20 21:03:56 +00:00
status , _ , err := sockRequest ( "POST" , "/containers/" + ContainerID + "/pause" , nil )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2015-04-10 01:14:01 +00:00
pausedContainers , err := getSliceOfPausedContainers ( )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "error thrown while checking if containers were paused: %v" , err )
2015-04-10 01:14:01 +00:00
}
if len ( pausedContainers ) != 1 || stringid . TruncateID ( ContainerID ) != pausedContainers [ 0 ] {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "there should be one paused container and not %d" , len ( pausedContainers ) )
2015-04-10 01:14:01 +00:00
}
2015-04-20 21:03:56 +00:00
status , _ , err = sockRequest ( "POST" , "/containers/" + ContainerID + "/unpause" , nil )
c . Assert ( status , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
2015-04-10 01:14:01 +00:00
pausedContainers , err = getSliceOfPausedContainers ( )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "error thrown while checking if containers were paused: %v" , err )
2015-04-10 01:14:01 +00:00
}
if pausedContainers != nil {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "There should be no paused container." )
2015-04-10 01:14:01 +00:00
}
}
2015-04-14 21:14:29 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiTop ( c * check . C ) {
out , err := exec . Command ( dockerBinary , "run" , "-d" , "busybox" , "/bin/sh" , "-c" , "top" ) . CombinedOutput ( )
if err != nil {
c . Fatal ( err , out )
}
id := strings . TrimSpace ( string ( out ) )
2015-04-14 21:14:29 +00:00
if err := waitRun ( id ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 21:14:29 +00:00
}
type topResp struct {
Titles [ ] string
Processes [ ] [ ] string
}
var top topResp
2015-04-20 21:03:56 +00:00
status , b , err := sockRequest ( "GET" , "/containers/" + id + "/top?ps_args=aux" , nil )
c . Assert ( status , check . Equals , http . StatusOK )
c . Assert ( err , check . IsNil )
2015-04-14 21:14:29 +00:00
if err := json . Unmarshal ( b , & top ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-14 21:14:29 +00:00
}
if len ( top . Titles ) != 11 {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected 11 titles, found %d: %v" , len ( top . Titles ) , top . Titles )
2015-04-14 21:14:29 +00:00
}
if top . Titles [ 0 ] != "USER" || top . Titles [ 10 ] != "COMMAND" {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected `USER` at `Titles[0]` and `COMMAND` at Titles[10]: %v" , top . Titles )
2015-04-14 21:14:29 +00:00
}
if len ( top . Processes ) != 2 {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected 2 processes, found %d: %v" , len ( top . Processes ) , top . Processes )
2015-04-14 21:14:29 +00:00
}
2015-04-18 16:46:47 +00:00
if top . Processes [ 0 ] [ 10 ] != "/bin/sh -c top" {
c . Fatalf ( "expected `/bin/sh -c top`, found: %s" , top . Processes [ 0 ] [ 10 ] )
2015-04-14 21:14:29 +00:00
}
2015-04-18 16:46:47 +00:00
if top . Processes [ 1 ] [ 10 ] != "top" {
c . Fatalf ( "expected `top`, found: %s" , top . Processes [ 1 ] [ 10 ] )
2015-04-14 21:14:29 +00:00
}
}
2015-04-15 00:48:03 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiCommit ( c * check . C ) {
2015-04-25 12:46:47 +00:00
cName := "testapicommit"
out , err := exec . Command ( dockerBinary , "run" , "--name=" + cName , "busybox" , "/bin/sh" , "-c" , "touch /test" ) . CombinedOutput ( )
2015-04-18 16:46:47 +00:00
if err != nil {
c . Fatal ( err , out )
}
2015-04-15 00:48:03 +00:00
2015-04-26 16:50:25 +00:00
name := "TestContainerApiCommit"
2015-04-25 12:46:47 +00:00
status , b , err := sockRequest ( "POST" , "/commit?repo=" + name + "&testtag=tag&container=" + cName , nil )
2015-04-20 21:03:56 +00:00
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2015-04-15 00:48:03 +00:00
type resp struct {
Id string
}
var img resp
if err := json . Unmarshal ( b , & img ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-15 00:48:03 +00:00
}
2015-04-18 16:46:47 +00:00
cmd , err := inspectField ( img . Id , "Config.Cmd" )
if err != nil {
c . Fatal ( err )
}
2015-03-26 19:43:00 +00:00
if cmd != "{[/bin/sh -c touch /test]}" {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "got wrong Cmd from commit: %q" , cmd )
2015-04-15 00:48:03 +00:00
}
// sanity check, make sure the image is what we think it is
2015-04-18 16:46:47 +00:00
out , err = exec . Command ( dockerBinary , "run" , img . Id , "ls" , "/test" ) . CombinedOutput ( )
if err != nil {
2015-04-27 20:33:30 +00:00
c . Fatalf ( "error checking committed image: %v - %q" , err , string ( out ) )
2015-04-18 16:46:47 +00:00
}
2015-04-15 00:48:03 +00:00
}
2015-04-15 01:04:43 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiCreate ( c * check . C ) {
2015-04-15 01:04:43 +00:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Cmd" : [ ] string { "/bin/sh" , "-c" , "touch /test && ls /test" } ,
}
2015-04-20 21:03:56 +00:00
status , b , err := sockRequest ( "POST" , "/containers/create" , config )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2015-04-15 01:04:43 +00:00
type createResp struct {
Id string
}
var container createResp
if err := json . Unmarshal ( b , & container ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-15 01:04:43 +00:00
}
2015-04-18 16:46:47 +00:00
out , err := exec . Command ( dockerBinary , "start" , "-a" , container . Id ) . CombinedOutput ( )
if err != nil {
c . Fatal ( out , err )
}
if strings . TrimSpace ( string ( out ) ) != "/test" {
c . Fatalf ( "expected output `/test`, got %q" , out )
2015-04-15 01:04:43 +00:00
}
}
2015-04-15 01:55:04 +00:00
2015-04-22 11:03:57 +00:00
func ( s * DockerSuite ) TestContainerApiCreateWithHostName ( c * check . C ) {
var hostName = "test-host"
config := map [ string ] interface { } {
"Image" : "busybox" ,
"Hostname" : hostName ,
}
_ , b , err := sockRequest ( "POST" , "/containers/create" , config )
if err != nil && ! strings . Contains ( err . Error ( ) , "200 OK: 201" ) {
c . Fatal ( err )
}
type createResp struct {
Id string
}
var container createResp
if err := json . Unmarshal ( b , & container ) ; err != nil {
c . Fatal ( err )
}
var id = container . Id
_ , bodyGet , err := sockRequest ( "GET" , "/containers/" + id + "/json" , nil )
type configLocal struct {
Hostname string
}
type getResponse struct {
Id string
Config configLocal
}
var containerInfo getResponse
if err := json . Unmarshal ( bodyGet , & containerInfo ) ; err != nil {
c . Fatal ( err )
}
var hostNameActual = containerInfo . Config . Hostname
if hostNameActual != "test-host" {
c . Fatalf ( "Mismatched Hostname, Expected %v, Actual: %v " , hostName , hostNameActual )
}
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiVerifyHeader ( c * check . C ) {
2015-04-15 01:55:04 +00:00
config := map [ string ] interface { } {
"Image" : "busybox" ,
}
create := func ( ct string ) ( int , io . ReadCloser , error ) {
jsonData := bytes . NewBuffer ( nil )
if err := json . NewEncoder ( jsonData ) . Encode ( config ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-15 01:55:04 +00:00
}
return sockRequestRaw ( "POST" , "/containers/create" , jsonData , ct )
}
// Try with no content-type
2015-04-20 21:03:56 +00:00
status , body , err := create ( "" )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( err , check . IsNil )
2015-04-15 01:55:04 +00:00
body . Close ( )
2015-04-20 21:03:56 +00:00
2015-04-15 01:55:04 +00:00
// Try with wrong content-type
2015-04-20 21:03:56 +00:00
status , body , err = create ( "application/xml" )
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( err , check . IsNil )
2015-04-15 01:55:04 +00:00
body . Close ( )
// now application/json
2015-04-20 21:03:56 +00:00
status , body , err = create ( "application/json" )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2015-04-15 01:55:04 +00:00
body . Close ( )
}
2015-04-15 02:07:04 +00: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 16:46:47 +00:00
func ( s * DockerSuite ) TestContainerApiPostCreateNull ( c * check . C ) {
2015-04-15 02:07:04 +00:00
config := ` {
"Hostname" : "" ,
"Domainname" : "" ,
"Memory" : 0 ,
"MemorySwap" : 0 ,
"CpuShares" : 0 ,
"Cpuset" : null ,
"AttachStdin" : true ,
"AttachStdout" : true ,
"AttachStderr" : true ,
"PortSpecs" : null ,
"ExposedPorts" : { } ,
"Tty" : true ,
"OpenStdin" : true ,
"StdinOnce" : true ,
"Env" : [ ] ,
"Cmd" : "ls" ,
"Image" : "busybox" ,
"Volumes" : { } ,
"WorkingDir" : "" ,
"Entrypoint" : null ,
"NetworkDisabled" : false ,
"OnBuild" : null } `
2015-04-20 21:03:56 +00:00
status , body , err := sockRequestRaw ( "POST" , "/containers/create" , strings . NewReader ( config ) , "application/json" )
c . Assert ( status , check . Equals , http . StatusCreated )
c . Assert ( err , check . IsNil )
2015-04-15 02:07:04 +00:00
b , err := readBody ( body )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-15 02:07:04 +00:00
}
type createResp struct {
Id string
}
var container createResp
if err := json . Unmarshal ( b , & container ) ; err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-04-15 02:07:04 +00:00
}
out , err := inspectField ( container . Id , "HostConfig.CpusetCpus" )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err , out )
2015-04-15 02:07:04 +00:00
}
if out != "" {
2015-04-18 16:46:47 +00:00
c . Fatalf ( "expected empty string, got %q" , out )
2015-04-15 02:07:04 +00:00
}
}
2015-04-15 22:43:18 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestCreateWithTooLowMemoryLimit ( c * check . C ) {
2015-04-15 22:43:18 +00:00
config := ` {
"Image" : "busybox" ,
"Cmd" : "ls" ,
"OpenStdin" : true ,
"CpuShares" : 100 ,
"Memory" : 524287
} `
2015-04-20 21:03:56 +00:00
status , body , _ := sockRequestRaw ( "POST" , "/containers/create" , strings . NewReader ( config ) , "application/json" )
2015-04-15 22:43:18 +00:00
b , err2 := readBody ( body )
if err2 != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err2 )
2015-04-15 22:43:18 +00:00
}
2015-04-20 21:03:56 +00:00
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( strings . Contains ( string ( b ) , "Minimum memory limit allowed is 4MB" ) , check . Equals , true )
2015-04-15 22:43:18 +00:00
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestStartWithTooLowMemoryLimit ( c * check . C ) {
2015-04-15 22:43:18 +00:00
out , _ , err := runCommandWithOutput ( exec . Command ( dockerBinary , "create" , "busybox" ) )
if err != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err , out )
2015-04-15 22:43:18 +00:00
}
containerID := strings . TrimSpace ( out )
config := ` {
"CpuShares" : 100 ,
"Memory" : 524287
} `
2015-04-20 21:03:56 +00:00
status , body , _ := sockRequestRaw ( "POST" , "/containers/" + containerID + "/start" , strings . NewReader ( config ) , "application/json" )
2015-04-15 22:43:18 +00:00
b , err2 := readBody ( body )
if err2 != nil {
2015-04-18 16:46:47 +00:00
c . Fatal ( err2 )
2015-04-15 22:43:18 +00:00
}
2015-04-20 21:03:56 +00:00
c . Assert ( status , check . Equals , http . StatusInternalServerError )
c . Assert ( strings . Contains ( string ( b ) , "Minimum memory limit allowed is 4MB" ) , check . Equals , true )
2015-04-15 22:43:18 +00:00
}
2015-04-24 11:57:04 +00:00
func ( s * DockerSuite ) TestContainerApiRename ( c * check . C ) {
2015-04-26 16:50:25 +00:00
runCmd := exec . Command ( dockerBinary , "run" , "--name" , "TestContainerApiRename" , "-d" , "busybox" , "sh" )
2015-04-24 11:57:04 +00:00
out , _ , err := runCommandWithOutput ( runCmd )
c . Assert ( err , check . IsNil )
containerID := strings . TrimSpace ( out )
2015-04-26 16:50:25 +00:00
newName := "TestContainerApiRenameNew"
2015-04-24 11:57:04 +00:00
statusCode , _ , err := sockRequest ( "POST" , "/containers/" + containerID + "/rename?name=" + newName , nil )
// 204 No Content is expected, not 200
c . Assert ( statusCode , check . Equals , http . StatusNoContent )
c . Assert ( err , check . IsNil )
name , err := inspectField ( containerID , "Name" )
if name != "/" + newName {
c . Fatalf ( "Failed to rename container, expected %v, got %v. Container rename API failed" , newName , name )
}
}