github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/rkt/image/common.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 "fmt" 19 "net/url" 20 "os" 21 "path/filepath" 22 "reflect" 23 "strings" 24 "time" 25 26 "github.com/coreos/rkt/common/apps" 27 "github.com/coreos/rkt/pkg/keystore" 28 rktlog "github.com/coreos/rkt/pkg/log" 29 "github.com/coreos/rkt/rkt/config" 30 rktflag "github.com/coreos/rkt/rkt/flag" 31 "github.com/coreos/rkt/store" 32 33 "github.com/appc/spec/schema" 34 "github.com/appc/spec/schema/types" 35 "golang.org/x/crypto/openpgp" 36 ) 37 38 // action is a common type for Finder and Fetcher 39 type action struct { 40 // S is a store where images will be looked for or stored. 41 S *store.Store 42 // Ks is a keystore used for verification of the image 43 Ks *keystore.Keystore 44 // Headers is a map of headers which might be used for 45 // downloading via https protocol. 46 Headers map[string]config.Headerer 47 // DockerAuth is used for authenticating when fetching docker 48 // images. 49 DockerAuth map[string]config.BasicCredentials 50 // InsecureFlags is a set of flags for enabling some insecure 51 // functionality. For now it is mostly skipping image 52 // signature verification and TLS certificate verification. 53 InsecureFlags *rktflag.SecFlags 54 // Debug tells whether additional debug messages should be 55 // printed. 56 Debug bool 57 // TrustKeysFromHTTPS tells whether discovered keys downloaded 58 // via the https protocol can be trusted 59 TrustKeysFromHTTPS bool 60 61 // StoreOnly tells whether to avoid getting images from a 62 // local filesystem or a remote location. 63 StoreOnly bool 64 // NoStore tells whether to avoid getting images from the 65 // store. Note that the store can be still used as a cache. 66 NoStore bool 67 // NoCache tells to avoid getting images from the store 68 // completely. 69 NoCache bool 70 // WithDeps tells whether image dependencies should be 71 // downloaded too. 72 WithDeps bool 73 } 74 75 var ( 76 log *rktlog.Logger 77 stdout *rktlog.Logger = rktlog.New(os.Stdout, "", false) 78 ) 79 80 func ensureLogger(debug bool) { 81 if log == nil { 82 log = rktlog.New(os.Stderr, "image", debug) 83 } 84 } 85 86 // isReallyNil makes sure that the passed value is really really 87 // nil. So it returns true if value is plain nil or if it is e.g. an 88 // interface with non-nil type but nil-value (which normally is 89 // different from nil itself). 90 func isReallyNil(iface interface{}) bool { 91 // this catches the cases when you pass non-interface nil 92 // directly, like: 93 // 94 // isReallyNil(nil) 95 // var m map[string]string 96 // isReallyNil(m) 97 if iface == nil { 98 return true 99 } 100 // get a reflect value 101 v := reflect.ValueOf(iface) 102 // only channels, functions, interfaces, maps, pointers and 103 // slices are nillable 104 switch v.Kind() { 105 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 106 // this catches the cases when you pass some interface 107 // with nil value, like: 108 // 109 // var v io.Closer = func(){var f *os.File; return f}() 110 // isReallyNil(v) 111 return v.IsNil() 112 } 113 return false 114 } 115 116 // useCached checks if downloadTime plus maxAge is before/after the current time. 117 // return true if the cached image should be used, false otherwise. 118 func useCached(downloadTime time.Time, maxAge int) bool { 119 freshnessLifetime := int(time.Now().Sub(downloadTime).Seconds()) 120 if maxAge > 0 && freshnessLifetime < maxAge { 121 return true 122 } 123 return false 124 } 125 126 // ascURLFromImgURL creates a URL to a signature file from passed URL 127 // to an image. 128 func ascURLFromImgURL(u *url.URL) *url.URL { 129 copy := *u 130 copy.Path = ascPathFromImgPath(copy.Path) 131 return © 132 } 133 134 // ascPathFromImgPath creates a path to a signature file from passed 135 // path to an image. 136 func ascPathFromImgPath(path string) string { 137 return fmt.Sprintf("%s.aci.asc", strings.TrimSuffix(path, ".aci")) 138 } 139 140 // printIdentities prints a message that signature was verified. 141 func printIdentities(entity *openpgp.Entity) { 142 lines := []string{"signature verified:"} 143 for _, v := range entity.Identities { 144 lines = append(lines, fmt.Sprintf(" %s", v.Name)) 145 } 146 log.Print(strings.Join(lines, "\n")) 147 } 148 149 func guessImageType(image string) apps.AppImageType { 150 if _, err := types.NewHash(image); err == nil { 151 return apps.AppImageHash 152 } 153 if u, err := url.Parse(image); err == nil && u.Scheme != "" { 154 return apps.AppImageURL 155 } 156 if filepath.IsAbs(image) { 157 return apps.AppImagePath 158 } 159 160 // Well, at this point is basically heuristics time. The image 161 // parameter can be either a relative path or an image name. 162 163 // First, let's check if there is a colon in the image 164 // parameter. Colon often serves as a paths separator (like in 165 // the PATH environment variable), so if it exists, then it is 166 // highly unlikely that the image parameter is a path. Colon 167 // in this context is often used for specifying a version of 168 // an image, like in "example.com/reduce-worker:1.0.0". 169 if strings.ContainsRune(image, ':') { 170 return apps.AppImageName 171 } 172 173 // Second, let's check if there is a dot followed by a slash 174 // (./) - if so, it is likely that the image parameter is path 175 // like ./aci-in-this-dir or ../aci-in-parent-dir 176 if strings.Contains(image, "./") { 177 return apps.AppImagePath 178 } 179 180 // Third, let's check if the image parameter has an .aci 181 // extension. If so, likely a path like "stage1-coreos.aci". 182 if filepath.Ext(image) == schema.ACIExtension { 183 return apps.AppImagePath 184 } 185 186 // At this point, if the image parameter is something like 187 // "coreos.com/rkt/stage1-coreos" and you have a directory 188 // tree "coreos.com/rkt" in the current working directory and 189 // you meant the image parameter to point to the file 190 // "stage1-coreos" in this directory tree, then you better be 191 // off prepending the parameter with "./", because I'm gonna 192 // treat this as an image name otherwise. 193 return apps.AppImageName 194 }