github.com/eatbyte/docker@v1.6.0/graph/service.go (about) 1 package graph 2 3 import ( 4 "fmt" 5 "io" 6 7 log "github.com/Sirupsen/logrus" 8 "github.com/docker/docker/engine" 9 "github.com/docker/docker/image" 10 ) 11 12 func (s *TagStore) Install(eng *engine.Engine) error { 13 for name, handler := range map[string]engine.Handler{ 14 "image_set": s.CmdSet, 15 "tag": s.CmdTag, 16 "image_get": s.CmdGet, 17 "image_inspect": s.CmdLookup, 18 "image_tarlayer": s.CmdTarLayer, 19 "image_export": s.CmdImageExport, 20 "history": s.CmdHistory, 21 "images": s.CmdImages, 22 "viz": s.CmdViz, 23 "load": s.CmdLoad, 24 "import": s.CmdImport, 25 "pull": s.CmdPull, 26 "push": s.CmdPush, 27 } { 28 if err := eng.Register(name, handler); err != nil { 29 return fmt.Errorf("Could not register %q: %v", name, err) 30 } 31 } 32 return nil 33 } 34 35 // CmdSet stores a new image in the graph. 36 // Images are stored in the graph using 4 elements: 37 // - A user-defined ID 38 // - A collection of metadata describing the image 39 // - A directory tree stored as a tar archive (also called the "layer") 40 // - A reference to a "parent" ID on top of which the layer should be applied 41 // 42 // NOTE: even though the parent ID is only useful in relation to the layer and how 43 // to apply it (ie you could represent the full directory tree as 'parent_layer + layer', 44 // it is treated as a top-level property of the image. This is an artifact of early 45 // design and should probably be cleaned up in the future to simplify the design. 46 // 47 // Syntax: image_set ID 48 // Input: 49 // - Layer content must be streamed in tar format on stdin. An empty input is 50 // valid and represents a nil layer. 51 // 52 // - Image metadata must be passed in the command environment. 53 // 'json': a json-encoded object with all image metadata. 54 // It will be stored as-is, without any encoding/decoding artifacts. 55 // That is a requirement of the current registry client implementation, 56 // because a re-encoded json might invalidate the image checksum at 57 // the next upload, even with functionaly identical content. 58 func (s *TagStore) CmdSet(job *engine.Job) engine.Status { 59 if len(job.Args) != 1 { 60 return job.Errorf("usage: %s NAME", job.Name) 61 } 62 var ( 63 imgJSON = []byte(job.Getenv("json")) 64 layer = job.Stdin 65 ) 66 if len(imgJSON) == 0 { 67 return job.Errorf("mandatory key 'json' is not set") 68 } 69 // We have to pass an *image.Image object, even though it will be completely 70 // ignored in favor of the redundant json data. 71 // FIXME: the current prototype of Graph.Register is stupid and redundant. 72 img, err := image.NewImgJSON(imgJSON) 73 if err != nil { 74 return job.Error(err) 75 } 76 if err := s.graph.Register(img, layer); err != nil { 77 return job.Error(err) 78 } 79 return engine.StatusOK 80 } 81 82 // CmdGet returns information about an image. 83 // If the image doesn't exist, an empty object is returned, to allow 84 // checking for an image's existence. 85 func (s *TagStore) CmdGet(job *engine.Job) engine.Status { 86 if len(job.Args) != 1 { 87 return job.Errorf("usage: %s NAME", job.Name) 88 } 89 name := job.Args[0] 90 res := &engine.Env{} 91 img, err := s.LookupImage(name) 92 // Note: if the image doesn't exist, LookupImage returns 93 // nil, nil. 94 if err != nil { 95 return job.Error(err) 96 } 97 if img != nil { 98 // We don't directly expose all fields of the Image objects, 99 // to maintain a clean public API which we can maintain over 100 // time even if the underlying structure changes. 101 // We should have done this with the Image object to begin with... 102 // but we didn't, so now we're doing it here. 103 // 104 // Fields that we're probably better off not including: 105 // - Config/ContainerConfig. Those structs have the same sprawl problem, 106 // so we shouldn't include them wholesale either. 107 // - Comment: initially created to fulfill the "every image is a git commit" 108 // metaphor, in practice people either ignore it or use it as a 109 // generic description field which it isn't. On deprecation shortlist. 110 res.SetAuto("Created", img.Created) 111 res.SetJson("Author", img.Author) 112 res.Set("Os", img.OS) 113 res.Set("Architecture", img.Architecture) 114 res.Set("DockerVersion", img.DockerVersion) 115 res.SetJson("Id", img.ID) 116 res.SetJson("Parent", img.Parent) 117 } 118 res.WriteTo(job.Stdout) 119 return engine.StatusOK 120 } 121 122 // CmdLookup return an image encoded in JSON 123 func (s *TagStore) CmdLookup(job *engine.Job) engine.Status { 124 if len(job.Args) != 1 { 125 return job.Errorf("usage: %s NAME", job.Name) 126 } 127 name := job.Args[0] 128 if image, err := s.LookupImage(name); err == nil && image != nil { 129 if job.GetenvBool("raw") { 130 b, err := image.RawJson() 131 if err != nil { 132 return job.Error(err) 133 } 134 job.Stdout.Write(b) 135 return engine.StatusOK 136 } 137 138 out := &engine.Env{} 139 out.SetJson("Id", image.ID) 140 out.SetJson("Parent", image.Parent) 141 out.SetJson("Comment", image.Comment) 142 out.SetAuto("Created", image.Created) 143 out.SetJson("Container", image.Container) 144 out.SetJson("ContainerConfig", image.ContainerConfig) 145 out.Set("DockerVersion", image.DockerVersion) 146 out.SetJson("Author", image.Author) 147 out.SetJson("Config", image.Config) 148 out.Set("Architecture", image.Architecture) 149 out.Set("Os", image.OS) 150 out.SetInt64("Size", image.Size) 151 out.SetInt64("VirtualSize", image.GetParentsSize(0)+image.Size) 152 if _, err = out.WriteTo(job.Stdout); err != nil { 153 return job.Error(err) 154 } 155 return engine.StatusOK 156 } 157 return job.Errorf("No such image: %s", name) 158 } 159 160 // CmdTarLayer return the tarLayer of the image 161 func (s *TagStore) CmdTarLayer(job *engine.Job) engine.Status { 162 if len(job.Args) != 1 { 163 return job.Errorf("usage: %s NAME", job.Name) 164 } 165 name := job.Args[0] 166 if image, err := s.LookupImage(name); err == nil && image != nil { 167 fs, err := image.TarLayer() 168 if err != nil { 169 return job.Error(err) 170 } 171 defer fs.Close() 172 173 written, err := io.Copy(job.Stdout, fs) 174 if err != nil { 175 return job.Error(err) 176 } 177 log.Debugf("rendered layer for %s of [%d] size", image.ID, written) 178 return engine.StatusOK 179 } 180 return job.Errorf("No such image: %s", name) 181 }