2014-02-25 16:17:48 +00:00
package main
import (
2015-10-01 16:07:30 +00:00
"encoding/json"
2014-02-25 16:17:48 +00:00
"fmt"
2014-09-06 11:49:40 +00:00
"io/ioutil"
2014-02-25 16:17:48 +00:00
"os"
"os/exec"
2014-09-06 11:49:40 +00:00
"path/filepath"
"reflect"
2015-11-18 22:20:54 +00:00
"regexp"
2014-11-11 09:18:22 +00:00
"sort"
"strings"
2015-10-01 16:07:30 +00:00
"time"
2015-04-18 16:46:47 +00:00
2015-11-18 22:20:54 +00:00
"github.com/docker/distribution/digest"
2015-10-12 08:24:16 +00:00
"github.com/docker/docker/pkg/integration/checker"
2015-04-18 16:46:47 +00:00
"github.com/go-check/check"
2014-02-25 16:17:48 +00:00
)
2014-12-08 20:40:27 +00:00
// save a repo using gz compression and try to load it using stdout
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveXzAndLoadRepoStdout ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2015-05-16 14:59:53 +00:00
name := "test-save-xz-and-load-repo-stdout"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "true" )
2014-12-08 20:40:27 +00:00
repoName := "foobar-save-load-test-xz-gz"
2015-07-21 18:01:24 +00:00
out , _ := dockerCmd ( c , "commit" , name , repoName )
2014-12-08 20:40:27 +00:00
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "inspect" , repoName )
2014-12-08 20:40:27 +00:00
2015-02-14 22:25:13 +00:00
repoTarball , _ , err := runCommandPipelineWithOutput (
exec . Command ( dockerBinary , "save" , repoName ) ,
exec . Command ( "xz" , "-c" ) ,
exec . Command ( "gzip" , "-c" ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save repo: %v %v" , out , err ) )
2014-12-08 20:40:27 +00:00
deleteImages ( repoName )
2015-02-14 22:25:13 +00:00
loadCmd := exec . Command ( dockerBinary , "load" )
loadCmd . Stdin = strings . NewReader ( repoTarball )
2014-12-08 20:40:27 +00:00
out , _ , err = runCommandWithOutput ( loadCmd )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . NotNil , check . Commentf ( "expected error, but succeeded with no error and output: %v" , out ) )
2014-12-08 20:40:27 +00:00
2015-07-27 18:13:25 +00:00
after , _ , err := dockerCmdWithError ( "inspect" , repoName )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . NotNil , check . Commentf ( "the repo should not exist: %v" , after ) )
2014-12-08 20:40:27 +00:00
}
// save a repo using xz+gz compression and try to load it using stdout
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveXzGzAndLoadRepoStdout ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2015-05-16 14:59:53 +00:00
name := "test-save-xz-gz-and-load-repo-stdout"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "true" )
2014-12-08 20:40:27 +00:00
repoName := "foobar-save-load-test-xz-gz"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "commit" , name , repoName )
2014-12-08 20:40:27 +00:00
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "inspect" , repoName )
2014-12-08 20:40:27 +00:00
2015-07-21 18:01:24 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-02-14 22:25:13 +00:00
exec . Command ( dockerBinary , "save" , repoName ) ,
exec . Command ( "xz" , "-c" ) ,
exec . Command ( "gzip" , "-c" ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save repo: %v %v" , out , err ) )
2014-12-08 20:40:27 +00:00
deleteImages ( repoName )
2015-02-14 22:25:13 +00:00
loadCmd := exec . Command ( dockerBinary , "load" )
loadCmd . Stdin = strings . NewReader ( out )
2014-12-08 20:40:27 +00:00
out , _ , err = runCommandWithOutput ( loadCmd )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . NotNil , check . Commentf ( "expected error, but succeeded with no error and output: %v" , out ) )
2014-12-08 20:40:27 +00:00
2015-07-27 18:13:25 +00:00
after , _ , err := dockerCmdWithError ( "inspect" , repoName )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . NotNil , check . Commentf ( "the repo should not exist: %v" , after ) )
2014-12-08 20:40:27 +00:00
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveSingleTag ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2014-07-07 18:58:27 +00:00
repoName := "foobar-save-single-tag-test"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "tag" , "busybox:latest" , fmt . Sprintf ( "%v:latest" , repoName ) )
2014-07-07 18:58:27 +00:00
2015-07-21 18:01:24 +00:00
out , _ := dockerCmd ( c , "images" , "-q" , "--no-trunc" , repoName )
2015-04-06 13:21:18 +00:00
cleanedImageID := strings . TrimSpace ( out )
2014-07-07 18:58:27 +00:00
2015-07-21 18:01:24 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-02-14 22:25:13 +00:00
exec . Command ( dockerBinary , "save" , fmt . Sprintf ( "%v:latest" , repoName ) ) ,
exec . Command ( "tar" , "t" ) ,
exec . Command ( "grep" , "-E" , fmt . Sprintf ( "(^repositories$|%v)" , cleanedImageID ) ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save repo with image ID and 'repositories' file: %s, %v" , out , err ) )
2014-07-07 18:58:27 +00:00
}
2015-10-01 16:07:30 +00:00
func ( s * DockerSuite ) TestSaveCheckTimes ( c * check . C ) {
2016-01-08 21:49:43 +00:00
testRequires ( c , DaemonIsLinux )
2015-10-01 16:07:30 +00:00
repoName := "busybox:latest"
out , _ := dockerCmd ( c , "inspect" , repoName )
data := [ ] struct {
ID string
Created time . Time
} { }
err := json . Unmarshal ( [ ] byte ( out ) , & data )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to marshal from %q: err %v" , repoName , err ) )
c . Assert ( len ( data ) , checker . Not ( checker . Equals ) , 0 , check . Commentf ( "failed to marshal the data from %q" , repoName ) )
2015-10-01 16:07:30 +00:00
tarTvTimeFormat := "2006-01-02 15:04"
out , _ , err = runCommandPipelineWithOutput (
exec . Command ( dockerBinary , "save" , repoName ) ,
exec . Command ( "tar" , "tv" ) ,
2015-11-18 22:20:54 +00:00
exec . Command ( "grep" , "-E" , fmt . Sprintf ( "%s %s" , data [ 0 ] . Created . Format ( tarTvTimeFormat ) , digest . Digest ( data [ 0 ] . ID ) . Hex ( ) ) ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save repo with image ID and 'repositories' file: %s, %v" , out , err ) )
2015-10-01 16:07:30 +00:00
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveImageId ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2014-07-07 18:58:27 +00:00
repoName := "foobar-save-image-id-test"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "tag" , "emptyfs:latest" , fmt . Sprintf ( "%v:latest" , repoName ) )
2014-07-07 18:58:27 +00:00
2015-07-21 18:01:24 +00:00
out , _ := dockerCmd ( c , "images" , "-q" , "--no-trunc" , repoName )
2015-11-18 22:20:54 +00:00
cleanedLongImageID := strings . TrimPrefix ( strings . TrimSpace ( out ) , "sha256:" )
2014-07-07 18:58:27 +00:00
2015-07-21 18:01:24 +00:00
out , _ = dockerCmd ( c , "images" , "-q" , repoName )
2015-04-06 13:21:18 +00:00
cleanedShortImageID := strings . TrimSpace ( out )
2014-07-07 18:58:27 +00:00
2015-08-22 12:06:48 +00:00
// Make sure IDs are not empty
2015-10-12 08:24:16 +00:00
c . Assert ( cleanedLongImageID , checker . Not ( check . Equals ) , "" , check . Commentf ( "Id should not be empty." ) )
c . Assert ( cleanedShortImageID , checker . Not ( check . Equals ) , "" , check . Commentf ( "Id should not be empty." ) )
2015-08-22 12:06:48 +00:00
2015-02-14 22:25:13 +00:00
saveCmd := exec . Command ( dockerBinary , "save" , cleanedShortImageID )
tarCmd := exec . Command ( "tar" , "t" )
2015-07-21 18:01:24 +00:00
var err error
2015-02-14 22:25:13 +00:00
tarCmd . Stdin , err = saveCmd . StdoutPipe ( )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "cannot set stdout pipe for tar: %v" , err ) )
2015-02-14 22:25:13 +00:00
grepCmd := exec . Command ( "grep" , cleanedLongImageID )
grepCmd . Stdin , err = tarCmd . StdoutPipe ( )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "cannot set stdout pipe for grep: %v" , err ) )
2014-07-07 18:58:27 +00:00
2015-10-12 08:24:16 +00:00
c . Assert ( tarCmd . Start ( ) , checker . IsNil , check . Commentf ( "tar failed with error: %v" , err ) )
c . Assert ( saveCmd . Start ( ) , checker . IsNil , check . Commentf ( "docker save failed with error: %v" , err ) )
2015-02-24 18:33:18 +00:00
defer func ( ) {
saveCmd . Wait ( )
tarCmd . Wait ( )
dockerCmd ( c , "rmi" , repoName )
} ( )
2015-02-14 22:25:13 +00:00
out , _ , err = runCommandWithOutput ( grepCmd )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save repo with image ID: %s, %v" , out , err ) )
2014-07-07 18:58:27 +00:00
}
2014-06-17 01:01:38 +00:00
// save a repo and try to load it using flags
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveAndLoadRepoFlags ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2015-05-16 14:59:53 +00:00
name := "test-save-and-load-repo-flags"
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "run" , "--name" , name , "busybox" , "true" )
2014-06-17 01:01:38 +00:00
repoName := "foobar-save-load-test"
2015-02-14 22:25:13 +00:00
deleteImages ( repoName )
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "commit" , name , repoName )
2014-06-17 01:01:38 +00:00
2015-07-21 18:01:24 +00:00
before , _ := dockerCmd ( c , "inspect" , repoName )
2014-06-17 01:01:38 +00:00
2015-07-21 18:01:24 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-02-14 22:25:13 +00:00
exec . Command ( dockerBinary , "save" , repoName ) ,
exec . Command ( dockerBinary , "load" ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save and load repo: %s, %v" , out , err ) )
2014-06-17 01:01:38 +00:00
2015-07-21 18:01:24 +00:00
after , _ := dockerCmd ( c , "inspect" , repoName )
2015-10-12 08:24:16 +00:00
c . Assert ( before , checker . Equals , after , check . Commentf ( "inspect is not the same after a save / load" ) )
2014-02-25 16:17:48 +00:00
}
2014-08-29 01:33:13 +00:00
2016-03-04 10:05:34 +00:00
func ( s * DockerSuite ) TestSaveWithNoExistImage ( c * check . C ) {
testRequires ( c , DaemonIsLinux )
imgName := "foobar-non-existing-image"
out , _ , err := dockerCmdWithError ( "save" , "-o" , "test-img.tar" , imgName )
c . Assert ( err , checker . NotNil , check . Commentf ( "save image should fail for non-existing image" ) )
c . Assert ( out , checker . Contains , fmt . Sprintf ( "No such image: %s" , imgName ) )
}
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveMultipleNames ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2014-08-29 01:33:13 +00:00
repoName := "foobar-save-multi-name-test"
// Make one image
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "tag" , "emptyfs:latest" , fmt . Sprintf ( "%v-one:latest" , repoName ) )
2014-11-17 16:05:49 +00:00
2014-08-29 01:33:13 +00:00
// Make two images
2015-07-21 18:01:24 +00:00
dockerCmd ( c , "tag" , "emptyfs:latest" , fmt . Sprintf ( "%v-two:latest" , repoName ) )
2014-08-29 01:33:13 +00:00
2015-07-21 18:01:24 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-02-14 22:25:13 +00:00
exec . Command ( dockerBinary , "save" , fmt . Sprintf ( "%v-one" , repoName ) , fmt . Sprintf ( "%v-two:latest" , repoName ) ) ,
exec . Command ( "tar" , "xO" , "repositories" ) ,
exec . Command ( "grep" , "-q" , "-E" , "(-one|-two)" ) ,
)
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save multiple repos: %s, %v" , out , err ) )
2014-08-29 01:33:13 +00:00
}
2014-09-06 11:49:40 +00:00
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveRepoWithMultipleImages ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2014-11-11 09:18:22 +00:00
makeImage := func ( from string , tag string ) string {
var (
out string
)
2015-07-21 18:01:24 +00:00
out , _ = dockerCmd ( c , "run" , "-d" , from , "true" )
2015-04-06 13:21:18 +00:00
cleanedContainerID := strings . TrimSpace ( out )
2014-11-11 09:18:22 +00:00
2015-07-21 18:01:24 +00:00
out , _ = dockerCmd ( c , "commit" , cleanedContainerID , tag )
2015-04-06 13:21:18 +00:00
imageID := strings . TrimSpace ( out )
2014-11-11 09:18:22 +00:00
return imageID
}
repoName := "foobar-save-multi-images-test"
tagFoo := repoName + ":foo"
tagBar := repoName + ":bar"
idFoo := makeImage ( "busybox:latest" , tagFoo )
idBar := makeImage ( "busybox:latest" , tagBar )
deleteImages ( repoName )
// create the archive
2015-02-14 22:25:13 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-11-18 22:20:54 +00:00
exec . Command ( dockerBinary , "save" , repoName , "busybox:latest" ) ,
exec . Command ( "tar" , "t" ) )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save multiple images: %s, %v" , out , err ) )
2015-11-18 22:20:54 +00:00
lines := strings . Split ( strings . TrimSpace ( out ) , "\n" )
var actual [ ] string
for _ , l := range lines {
if regexp . MustCompile ( "^[a-f0-9]{64}\\.json$" ) . Match ( [ ] byte ( l ) ) {
actual = append ( actual , strings . TrimSuffix ( l , ".json" ) )
}
}
2014-11-11 09:18:22 +00:00
// make the list of expected layers
2016-01-28 14:19:25 +00:00
out = inspectField ( c , "busybox:latest" , "Id" )
2015-11-18 22:20:54 +00:00
expected := [ ] string { strings . TrimSpace ( out ) , idFoo , idBar }
// prefixes are not in tar
for i := range expected {
expected [ i ] = digest . Digest ( expected [ i ] ) . Hex ( )
}
2014-11-11 09:18:22 +00:00
sort . Strings ( actual )
sort . Strings ( expected )
2015-11-18 22:20:54 +00:00
c . Assert ( actual , checker . DeepEquals , expected , check . Commentf ( "archive does not contains the right layers: got %v, expected %v, output: %q" , actual , expected , out ) )
2014-11-11 09:18:22 +00:00
}
2014-09-06 11:49:40 +00:00
// Issue #6722 #5892 ensure directories are included in changes
2015-04-18 16:46:47 +00:00
func ( s * DockerSuite ) TestSaveDirectoryPermissions ( c * check . C ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2014-09-06 11:49:40 +00:00
layerEntries := [ ] string { "opt/" , "opt/a/" , "opt/a/b/" , "opt/a/b/c" }
2014-09-19 18:08:57 +00:00
layerEntriesAUFS := [ ] string { "./" , ".wh..wh.aufs" , ".wh..wh.orph/" , ".wh..wh.plnk/" , "opt/" , "opt/a/" , "opt/a/b/" , "opt/a/b/c" }
2014-09-06 11:49:40 +00:00
name := "save-directory-permissions"
tmpDir , err := ioutil . TempDir ( "" , "save-layers-with-directories" )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to create temporary directory: %s" , err ) )
2014-10-14 20:22:06 +00:00
extractionDirectory := filepath . Join ( tmpDir , "image-extraction-dir" )
os . Mkdir ( extractionDirectory , 0777 )
2014-09-06 11:49:40 +00:00
defer os . RemoveAll ( tmpDir )
_ , err = buildImage ( name ,
` FROM busybox
RUN adduser - D user && mkdir - p / opt / a / b && chown - R user : user / opt / a
RUN touch / opt / a / b / c && chown user : user / opt / a / b / c ` ,
true )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "%v" , err ) )
2014-09-06 11:49:40 +00:00
2015-10-12 08:24:16 +00:00
out , _ , err := runCommandPipelineWithOutput (
2015-02-24 23:52:06 +00:00
exec . Command ( dockerBinary , "save" , name ) ,
exec . Command ( "tar" , "-xf" , "-" , "-C" , extractionDirectory ) ,
2015-10-12 08:24:16 +00:00
)
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to save and extract image: %s" , out ) )
2014-09-06 11:49:40 +00:00
dirs , err := ioutil . ReadDir ( extractionDirectory )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to get a listing of the layer directories: %s" , err ) )
2014-09-06 11:49:40 +00:00
found := false
for _ , entry := range dirs {
2015-02-25 23:53:07 +00:00
var entriesSansDev [ ] string
2014-09-06 11:49:40 +00:00
if entry . IsDir ( ) {
layerPath := filepath . Join ( extractionDirectory , entry . Name ( ) , "layer.tar" )
f , err := os . Open ( layerPath )
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "failed to open %s: %s" , layerPath , err ) )
2014-09-06 11:49:40 +00:00
2015-07-22 12:59:24 +00:00
entries , err := listTar ( f )
2015-02-02 00:42:35 +00:00
for _ , e := range entries {
if ! strings . Contains ( e , "dev/" ) {
entriesSansDev = append ( entriesSansDev , e )
}
}
2015-10-12 08:24:16 +00:00
c . Assert ( err , checker . IsNil , check . Commentf ( "encountered error while listing tar entries: %s" , err ) )
2014-09-06 11:49:40 +00:00
2015-02-02 00:42:35 +00:00
if reflect . DeepEqual ( entriesSansDev , layerEntries ) || reflect . DeepEqual ( entriesSansDev , layerEntriesAUFS ) {
2014-09-06 11:49:40 +00:00
found = true
2014-09-19 18:08:57 +00:00
break
2014-09-06 11:49:40 +00:00
}
}
}
2015-10-12 08:24:16 +00:00
c . Assert ( found , checker . Equals , true , check . Commentf ( "failed to find the layer with the right content listing" ) )
2014-09-06 11:49:40 +00:00
}
2015-11-24 01:20:44 +00:00
// Test loading a weird image where one of the layers is of zero size.
// The layer.tar file is actually zero bytes, no padding or anything else.
// See issue: 18170
func ( s * DockerSuite ) TestLoadZeroSizeLayer ( c * check . C ) {
testRequires ( c , DaemonIsLinux )
dockerCmd ( c , "load" , "-i" , "fixtures/load/emptyLayer.tar" )
}
2016-03-21 20:52:36 +00:00
func ( s * DockerSuite ) TestSaveLoadParents ( c * check . C ) {
testRequires ( c , DaemonIsLinux )
makeImage := func ( from string , addfile string ) string {
var (
out string
)
out , _ = dockerCmd ( c , "run" , "-d" , from , "touch" , addfile )
cleanedContainerID := strings . TrimSpace ( out )
out , _ = dockerCmd ( c , "commit" , cleanedContainerID )
imageID := strings . TrimSpace ( out )
2016-04-07 04:57:32 +00:00
dockerCmd ( c , "rm" , "-f" , cleanedContainerID )
2016-03-21 20:52:36 +00:00
return imageID
}
idFoo := makeImage ( "busybox" , "foo" )
idBar := makeImage ( idFoo , "bar" )
tmpDir , err := ioutil . TempDir ( "" , "save-load-parents" )
c . Assert ( err , checker . IsNil )
defer os . RemoveAll ( tmpDir )
c . Log ( "tmpdir" , tmpDir )
outfile := filepath . Join ( tmpDir , "out.tar" )
dockerCmd ( c , "save" , "-o" , outfile , idBar , idFoo )
dockerCmd ( c , "rmi" , idBar )
dockerCmd ( c , "load" , "-i" , outfile )
inspectOut := inspectField ( c , idBar , "Parent" )
c . Assert ( inspectOut , checker . Equals , idFoo )
inspectOut = inspectField ( c , idFoo , "Parent" )
c . Assert ( inspectOut , checker . Equals , "" )
}