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