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