github.com/pritambaral/docker@v1.4.2-0.20150120174542-b2fe1b3dd952/image/image.go (about) 1 package image 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path" 9 "strconv" 10 "time" 11 12 log "github.com/Sirupsen/logrus" 13 "github.com/docker/docker/pkg/archive" 14 "github.com/docker/docker/pkg/tarsum" 15 "github.com/docker/docker/runconfig" 16 "github.com/docker/docker/utils" 17 ) 18 19 // Set the max depth to the aufs default that most 20 // kernels are compiled with 21 // For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk 22 const MaxImageDepth = 127 23 24 type Image struct { 25 ID string `json:"id"` 26 Parent string `json:"parent,omitempty"` 27 Comment string `json:"comment,omitempty"` 28 Created time.Time `json:"created"` 29 Container string `json:"container,omitempty"` 30 ContainerConfig runconfig.Config `json:"container_config,omitempty"` 31 DockerVersion string `json:"docker_version,omitempty"` 32 Author string `json:"author,omitempty"` 33 Config *runconfig.Config `json:"config,omitempty"` 34 Architecture string `json:"architecture,omitempty"` 35 OS string `json:"os,omitempty"` 36 Checksum string `json:"checksum"` 37 Size int64 38 39 graph Graph 40 } 41 42 func LoadImage(root string) (*Image, error) { 43 // Open the JSON file to decode by streaming 44 jsonSource, err := os.Open(jsonPath(root)) 45 if err != nil { 46 return nil, err 47 } 48 defer jsonSource.Close() 49 50 img := &Image{} 51 dec := json.NewDecoder(jsonSource) 52 53 // Decode the JSON data 54 if err := dec.Decode(img); err != nil { 55 return nil, err 56 } 57 if err := utils.ValidateID(img.ID); err != nil { 58 return nil, err 59 } 60 61 if buf, err := ioutil.ReadFile(path.Join(root, "layersize")); err != nil { 62 if !os.IsNotExist(err) { 63 return nil, err 64 } 65 // If the layersize file does not exist then set the size to a negative number 66 // because a layer size of 0 (zero) is valid 67 img.Size = -1 68 } else { 69 // Using Atoi here instead would temporarily convert the size to a machine 70 // dependent integer type, which causes images larger than 2^31 bytes to 71 // display negative sizes on 32-bit machines: 72 size, err := strconv.ParseInt(string(buf), 10, 64) 73 if err != nil { 74 return nil, err 75 } 76 img.Size = int64(size) 77 } 78 79 return img, nil 80 } 81 82 // StoreImage stores file system layer data for the given image to the 83 // image's registered storage driver. Image metadata is stored in a file 84 // at the specified root directory. This function also computes the TarSum 85 // of `layerData` (currently using tarsum.dev). 86 func StoreImage(img *Image, layerData archive.ArchiveReader, root string) error { 87 // Store the layer 88 var ( 89 size int64 90 err error 91 driver = img.graph.Driver() 92 layerTarSum tarsum.TarSum 93 ) 94 95 // If layerData is not nil, unpack it into the new layer 96 if layerData != nil { 97 // If the image doesn't have a checksum, we should add it. The layer 98 // checksums are verified when they are pulled from a remote, but when 99 // a container is committed it should be added here. 100 if img.Checksum == "" { 101 layerDataDecompressed, err := archive.DecompressStream(layerData) 102 if err != nil { 103 return err 104 } 105 defer layerDataDecompressed.Close() 106 107 if layerTarSum, err = tarsum.NewTarSum(layerDataDecompressed, true, tarsum.VersionDev); err != nil { 108 return err 109 } 110 111 if size, err = driver.ApplyDiff(img.ID, img.Parent, layerTarSum); err != nil { 112 return err 113 } 114 115 img.Checksum = layerTarSum.Sum(nil) 116 } else if size, err = driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil { 117 return err 118 } 119 120 } 121 122 img.Size = size 123 if err := img.SaveSize(root); err != nil { 124 return err 125 } 126 127 f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600)) 128 if err != nil { 129 return err 130 } 131 132 defer f.Close() 133 134 return json.NewEncoder(f).Encode(img) 135 } 136 137 func (img *Image) SetGraph(graph Graph) { 138 img.graph = graph 139 } 140 141 // SaveSize stores the current `size` value of `img` in the directory `root`. 142 func (img *Image) SaveSize(root string) error { 143 if err := ioutil.WriteFile(path.Join(root, "layersize"), []byte(strconv.Itoa(int(img.Size))), 0600); err != nil { 144 return fmt.Errorf("Error storing image size in %s/layersize: %s", root, err) 145 } 146 return nil 147 } 148 149 func jsonPath(root string) string { 150 return path.Join(root, "json") 151 } 152 153 func (img *Image) RawJson() ([]byte, error) { 154 root, err := img.root() 155 if err != nil { 156 return nil, fmt.Errorf("Failed to get root for image %s: %s", img.ID, err) 157 } 158 fh, err := os.Open(jsonPath(root)) 159 if err != nil { 160 return nil, fmt.Errorf("Failed to open json for image %s: %s", img.ID, err) 161 } 162 buf, err := ioutil.ReadAll(fh) 163 if err != nil { 164 return nil, fmt.Errorf("Failed to read json for image %s: %s", img.ID, err) 165 } 166 return buf, nil 167 } 168 169 // TarLayer returns a tar archive of the image's filesystem layer. 170 func (img *Image) TarLayer() (arch archive.Archive, err error) { 171 if img.graph == nil { 172 return nil, fmt.Errorf("Can't load storage driver for unregistered image %s", img.ID) 173 } 174 175 driver := img.graph.Driver() 176 177 return driver.Diff(img.ID, img.Parent) 178 } 179 180 // Image includes convenience proxy functions to its graph 181 // These functions will return an error if the image is not registered 182 // (ie. if image.graph == nil) 183 func (img *Image) History() ([]*Image, error) { 184 var parents []*Image 185 if err := img.WalkHistory( 186 func(img *Image) error { 187 parents = append(parents, img) 188 return nil 189 }, 190 ); err != nil { 191 return nil, err 192 } 193 return parents, nil 194 } 195 196 func (img *Image) WalkHistory(handler func(*Image) error) (err error) { 197 currentImg := img 198 for currentImg != nil { 199 if handler != nil { 200 if err := handler(currentImg); err != nil { 201 return err 202 } 203 } 204 currentImg, err = currentImg.GetParent() 205 if err != nil { 206 return fmt.Errorf("Error while getting parent image: %v", err) 207 } 208 } 209 return nil 210 } 211 212 func (img *Image) GetParent() (*Image, error) { 213 if img.Parent == "" { 214 return nil, nil 215 } 216 if img.graph == nil { 217 return nil, fmt.Errorf("Can't lookup parent of unregistered image") 218 } 219 return img.graph.Get(img.Parent) 220 } 221 222 func (img *Image) root() (string, error) { 223 if img.graph == nil { 224 return "", fmt.Errorf("Can't lookup root of unregistered image") 225 } 226 return img.graph.ImageRoot(img.ID), nil 227 } 228 229 func (img *Image) GetParentsSize(size int64) int64 { 230 parentImage, err := img.GetParent() 231 if err != nil || parentImage == nil { 232 return size 233 } 234 size += parentImage.Size 235 return parentImage.GetParentsSize(size) 236 } 237 238 // Depth returns the number of parents for a 239 // current image 240 func (img *Image) Depth() (int, error) { 241 var ( 242 count = 0 243 parent = img 244 err error 245 ) 246 247 for parent != nil { 248 count++ 249 parent, err = parent.GetParent() 250 if err != nil { 251 return -1, err 252 } 253 } 254 return count, nil 255 } 256 257 // CheckDepth returns an error if the depth of an image, as returned 258 // by ImageDepth, is too large to support creating a container from it 259 // on this daemon. 260 func (img *Image) CheckDepth() error { 261 // We add 2 layers to the depth because the container's rw and 262 // init layer add to the restriction 263 depth, err := img.Depth() 264 if err != nil { 265 return err 266 } 267 if depth+2 >= MaxImageDepth { 268 return fmt.Errorf("Cannot create container with more than %d parents", MaxImageDepth) 269 } 270 return nil 271 } 272 273 // Build an Image object from raw json data 274 func NewImgJSON(src []byte) (*Image, error) { 275 ret := &Image{} 276 277 log.Debugf("Json string: {%s}", src) 278 // FIXME: Is there a cleaner way to "purify" the input json? 279 if err := json.Unmarshal(src, ret); err != nil { 280 return nil, err 281 } 282 return ret, nil 283 }