github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/rkt/image/dockerfetcher.go (about) 1 // Copyright 2015 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package image 16 17 import ( 18 "errors" 19 "fmt" 20 "io/ioutil" 21 "net/url" 22 "os" 23 "path" 24 "strings" 25 "time" 26 27 "github.com/coreos/rkt/rkt/config" 28 rktflag "github.com/coreos/rkt/rkt/flag" 29 "github.com/coreos/rkt/store" 30 "github.com/hashicorp/errwrap" 31 32 docker2aci "github.com/appc/docker2aci/lib" 33 d2acommon "github.com/appc/docker2aci/lib/common" 34 ) 35 36 // dockerFetcher is used to fetch images from docker:// URLs. It uses 37 // a docker2aci library to perform this task. 38 type dockerFetcher struct { 39 // TODO(krnowak): Fix the docs when we support docker image 40 // verification. Will that ever happen? 41 // InsecureFlags tells which insecure functionality should 42 // be enabled. No image verification must be true for now. 43 InsecureFlags *rktflag.SecFlags 44 DockerAuth map[string]config.BasicCredentials 45 S *store.Store 46 Debug bool 47 } 48 49 // GetHash uses docker2aci to download the image and convert it to 50 // ACI, then stores it in the store and returns the hash. 51 func (f *dockerFetcher) GetHash(u *url.URL) (string, error) { 52 ensureLogger(f.Debug) 53 dockerURL := d2acommon.ParseDockerURL(path.Join(u.Host, u.Path)) 54 latest := dockerURL.Tag == "latest" 55 return f.fetchImageFrom(u, latest) 56 } 57 58 func (f *dockerFetcher) fetchImageFrom(u *url.URL, latest bool) (string, error) { 59 if !f.InsecureFlags.SkipImageCheck() { 60 return "", fmt.Errorf("signature verification for docker images is not supported (try --insecure-options=image)") 61 } 62 63 if f.Debug { 64 log.Printf("fetching image from %s", u.String()) 65 } 66 67 aciFile, err := f.fetch(u) 68 if err != nil { 69 return "", err 70 } 71 // At this point, the ACI file is removed, but it is kept 72 // alive, because we have an fd to it opened. 73 defer aciFile.Close() 74 75 key, err := f.S.WriteACI(aciFile, latest) 76 if err != nil { 77 return "", err 78 } 79 80 // TODO(krnowak): Consider dropping the signature URL part 81 // from store.Remote. It is not used anywhere and the data 82 // stored here is useless. 83 newRem := store.NewRemote(u.String(), ascURLFromImgURL(u).String()) 84 newRem.BlobKey = key 85 newRem.DownloadTime = time.Now() 86 err = f.S.WriteRemote(newRem) 87 if err != nil { 88 return "", err 89 } 90 91 return key, nil 92 } 93 94 func (f *dockerFetcher) fetch(u *url.URL) (*os.File, error) { 95 tmpDir, err := f.getTmpDir() 96 if err != nil { 97 return nil, err 98 } 99 defer os.RemoveAll(tmpDir) 100 101 registryURL := strings.TrimPrefix(u.String(), "docker://") 102 user, password := f.getCreds(registryURL) 103 acis, err := docker2aci.Convert(registryURL, true /* squash */, tmpDir, tmpDir, d2acommon.NoCompression, user, password, f.InsecureFlags.AllowHTTP()) 104 if err != nil { 105 return nil, errwrap.Wrap(errors.New("error converting docker image to ACI"), err) 106 } 107 108 aciFile, err := os.Open(acis[0]) 109 if err != nil { 110 return nil, errwrap.Wrap(errors.New("error opening squashed ACI file"), err) 111 } 112 113 return aciFile, nil 114 } 115 116 func (f *dockerFetcher) getTmpDir() (string, error) { 117 storeTmpDir, err := f.S.TmpDir() 118 if err != nil { 119 return "", errwrap.Wrap(errors.New("error creating temporary dir for docker to ACI conversion"), err) 120 } 121 return ioutil.TempDir(storeTmpDir, "docker2aci-") 122 } 123 124 func (f *dockerFetcher) getCreds(registryURL string) (string, string) { 125 indexName := docker2aci.GetIndexName(registryURL) 126 if creds, ok := f.DockerAuth[indexName]; ok { 127 return creds.User, creds.Password 128 } 129 return "", "" 130 }