github.com/gondor/docker@v1.9.0-rc1/daemon/daemonbuilder/builder.go (about) 1 package daemonbuilder 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/api" 13 "github.com/docker/docker/builder" 14 "github.com/docker/docker/cliconfig" 15 "github.com/docker/docker/daemon" 16 "github.com/docker/docker/graph" 17 "github.com/docker/docker/image" 18 "github.com/docker/docker/pkg/archive" 19 "github.com/docker/docker/pkg/httputils" 20 "github.com/docker/docker/pkg/ioutils" 21 "github.com/docker/docker/pkg/parsers" 22 "github.com/docker/docker/pkg/progressreader" 23 "github.com/docker/docker/pkg/system" 24 "github.com/docker/docker/pkg/urlutil" 25 "github.com/docker/docker/registry" 26 "github.com/docker/docker/runconfig" 27 ) 28 29 // Docker implements builder.Docker for the docker Daemon object. 30 type Docker struct { 31 Daemon *daemon.Daemon 32 OutOld io.Writer 33 AuthConfigs map[string]cliconfig.AuthConfig 34 Archiver *archive.Archiver 35 } 36 37 // ensure Docker implements builder.Docker 38 var _ builder.Docker = Docker{} 39 40 // LookupImage looks up a Docker image referenced by `name`. 41 func (d Docker) LookupImage(name string) (*image.Image, error) { 42 return d.Daemon.GetImage(name) 43 } 44 45 // Pull tells Docker to pull image referenced by `name`. 46 func (d Docker) Pull(name string) (*image.Image, error) { 47 remote, tag := parsers.ParseRepositoryTag(name) 48 if tag == "" { 49 tag = "latest" 50 } 51 52 pullRegistryAuth := &cliconfig.AuthConfig{} 53 if len(d.AuthConfigs) > 0 { 54 // The request came with a full auth config file, we prefer to use that 55 repoInfo, err := d.Daemon.RegistryService.ResolveRepository(remote) 56 if err != nil { 57 return nil, err 58 } 59 60 resolvedConfig := registry.ResolveAuthConfig( 61 &cliconfig.ConfigFile{AuthConfigs: d.AuthConfigs}, 62 repoInfo.Index, 63 ) 64 pullRegistryAuth = &resolvedConfig 65 } 66 67 imagePullConfig := &graph.ImagePullConfig{ 68 AuthConfig: pullRegistryAuth, 69 OutStream: ioutils.NopWriteCloser(d.OutOld), 70 } 71 72 if err := d.Daemon.PullImage(remote, tag, imagePullConfig); err != nil { 73 return nil, err 74 } 75 76 return d.Daemon.GetImage(name) 77 } 78 79 // Container looks up a Docker container referenced by `id`. 80 func (d Docker) Container(id string) (*daemon.Container, error) { 81 return d.Daemon.Get(id) 82 } 83 84 // Create creates a new Docker container and returns potential warnings 85 func (d Docker) Create(cfg *runconfig.Config, hostCfg *runconfig.HostConfig) (*daemon.Container, []string, error) { 86 ccr, err := d.Daemon.ContainerCreate("", cfg, hostCfg, true) 87 if err != nil { 88 return nil, nil, err 89 } 90 container, err := d.Daemon.Get(ccr.ID) 91 if err != nil { 92 return nil, ccr.Warnings, err 93 } 94 return container, ccr.Warnings, container.Mount() 95 } 96 97 // Remove removes a container specified by `id`. 98 func (d Docker) Remove(id string, cfg *daemon.ContainerRmConfig) error { 99 return d.Daemon.ContainerRm(id, cfg) 100 } 101 102 // Commit creates a new Docker image from an existing Docker container. 103 func (d Docker) Commit(c *daemon.Container, cfg *daemon.ContainerCommitConfig) (*image.Image, error) { 104 return d.Daemon.Commit(c, cfg) 105 } 106 107 // Retain retains an image avoiding it to be removed or overwritten until a corresponding Release() call. 108 func (d Docker) Retain(sessionID, imgID string) { 109 d.Daemon.Graph().Retain(sessionID, imgID) 110 } 111 112 // Release releases a list of images that were retained for the time of a build. 113 func (d Docker) Release(sessionID string, activeImages []string) { 114 d.Daemon.Graph().Release(sessionID, activeImages...) 115 } 116 117 // Copy copies/extracts a source FileInfo to a destination path inside a container 118 // specified by a container object. 119 // TODO: make sure callers don't unnecessarily convert destPath with filepath.FromSlash (Copy does it already). 120 // Copy should take in abstract paths (with slashes) and the implementation should convert it to OS-specific paths. 121 func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo, decompress bool) error { 122 srcPath := src.Path() 123 destExists := true 124 rootUID, rootGID := d.Daemon.GetRemappedUIDGID() 125 126 // Work in daemon-local OS specific file paths 127 destPath = filepath.FromSlash(destPath) 128 129 dest, err := c.GetResourcePath(destPath) 130 if err != nil { 131 return err 132 } 133 134 // Preserve the trailing slash 135 // TODO: why are we appending another path separator if there was already one? 136 if strings.HasSuffix(destPath, string(os.PathSeparator)) || destPath == "." { 137 dest += string(os.PathSeparator) 138 } 139 140 destPath = dest 141 142 destStat, err := os.Stat(destPath) 143 if err != nil { 144 if !os.IsNotExist(err) { 145 logrus.Errorf("Error performing os.Stat on %s. %s", destPath, err) 146 return err 147 } 148 destExists = false 149 } 150 151 if src.IsDir() { 152 // copy as directory 153 if err := d.Archiver.CopyWithTar(srcPath, destPath); err != nil { 154 return err 155 } 156 return fixPermissions(srcPath, destPath, rootUID, rootGID, destExists) 157 } 158 if decompress { 159 // Only try to untar if it is a file and that we've been told to decompress (when ADD-ing a remote file) 160 161 // First try to unpack the source as an archive 162 // to support the untar feature we need to clean up the path a little bit 163 // because tar is very forgiving. First we need to strip off the archive's 164 // filename from the path but this is only added if it does not end in slash 165 tarDest := destPath 166 if strings.HasSuffix(tarDest, string(os.PathSeparator)) { 167 tarDest = filepath.Dir(destPath) 168 } 169 170 // try to successfully untar the orig 171 if err := d.Archiver.UntarPath(srcPath, tarDest); err == nil { 172 return nil 173 } else if err != io.EOF { 174 logrus.Debugf("Couldn't untar to %s: %v", tarDest, err) 175 } 176 } 177 178 // only needed for fixPermissions, but might as well put it before CopyFileWithTar 179 if destExists && destStat.IsDir() { 180 destPath = filepath.Join(destPath, filepath.Base(srcPath)) 181 } 182 183 if err := system.MkdirAll(filepath.Dir(destPath), 0755); err != nil { 184 return err 185 } 186 if err := d.Archiver.CopyFileWithTar(srcPath, destPath); err != nil { 187 return err 188 } 189 190 return fixPermissions(srcPath, destPath, rootUID, rootGID, destExists) 191 } 192 193 // GetCachedImage returns a reference to a cached image whose parent equals `parent` 194 // and runconfig equals `cfg`. A cache miss is expected to return an empty ID and a nil error. 195 func (d Docker) GetCachedImage(imgID string, cfg *runconfig.Config) (string, error) { 196 cache, err := d.Daemon.ImageGetCached(string(imgID), cfg) 197 if cache == nil || err != nil { 198 return "", err 199 } 200 return cache.ID, nil 201 } 202 203 // Following is specific to builder contexts 204 205 // DetectContextFromRemoteURL returns a context and in certain cases the name of the dockerfile to be used 206 // irrespective of user input. 207 // progressReader is only used if remoteURL is actually a URL (not empty, and not a Git endpoint). 208 func DetectContextFromRemoteURL(r io.ReadCloser, remoteURL string, progressReader *progressreader.Config) (context builder.ModifiableContext, dockerfileName string, err error) { 209 switch { 210 case remoteURL == "": 211 context, err = builder.MakeTarSumContext(r) 212 case urlutil.IsGitURL(remoteURL): 213 context, err = builder.MakeGitContext(remoteURL) 214 case urlutil.IsURL(remoteURL): 215 context, err = builder.MakeRemoteContext(remoteURL, map[string]func(io.ReadCloser) (io.ReadCloser, error){ 216 httputils.MimeTypes.TextPlain: func(rc io.ReadCloser) (io.ReadCloser, error) { 217 dockerfile, err := ioutil.ReadAll(rc) 218 if err != nil { 219 return nil, err 220 } 221 222 // dockerfileName is set to signal that the remote was interpreted as a single Dockerfile, in which case the caller 223 // should use dockerfileName as the new name for the Dockerfile, irrespective of any other user input. 224 dockerfileName = api.DefaultDockerfileName 225 226 // TODO: return a context without tarsum 227 return archive.Generate(dockerfileName, string(dockerfile)) 228 }, 229 // fallback handler (tar context) 230 "": func(rc io.ReadCloser) (io.ReadCloser, error) { 231 progressReader.In = rc 232 return progressReader, nil 233 }, 234 }) 235 default: 236 err = fmt.Errorf("remoteURL (%s) could not be recognized as URL", remoteURL) 237 } 238 return 239 }