github.com/akerouanton/docker@v1.11.0-rc3/image/v1/imagev1.go (about)

     1  package v1
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/Sirupsen/logrus"
    10  	"github.com/docker/distribution/digest"
    11  	"github.com/docker/docker/image"
    12  	"github.com/docker/docker/layer"
    13  	"github.com/docker/docker/pkg/version"
    14  )
    15  
    16  var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)
    17  
    18  // noFallbackMinVersion is the minimum version for which v1compatibility
    19  // information will not be marshaled through the Image struct to remove
    20  // blank fields.
    21  var noFallbackMinVersion = version.Version("1.8.3")
    22  
    23  // HistoryFromConfig creates a History struct from v1 configuration JSON
    24  func HistoryFromConfig(imageJSON []byte, emptyLayer bool) (image.History, error) {
    25  	h := image.History{}
    26  	var v1Image image.V1Image
    27  	if err := json.Unmarshal(imageJSON, &v1Image); err != nil {
    28  		return h, err
    29  	}
    30  
    31  	return image.History{
    32  		Author:     v1Image.Author,
    33  		Created:    v1Image.Created,
    34  		CreatedBy:  strings.Join(v1Image.ContainerConfig.Cmd, " "),
    35  		Comment:    v1Image.Comment,
    36  		EmptyLayer: emptyLayer,
    37  	}, nil
    38  }
    39  
    40  // CreateID creates an ID from v1 image, layerID and parent ID.
    41  // Used for backwards compatibility with old clients.
    42  func CreateID(v1Image image.V1Image, layerID layer.ChainID, parent digest.Digest) (digest.Digest, error) {
    43  	v1Image.ID = ""
    44  	v1JSON, err := json.Marshal(v1Image)
    45  	if err != nil {
    46  		return "", err
    47  	}
    48  
    49  	var config map[string]*json.RawMessage
    50  	if err := json.Unmarshal(v1JSON, &config); err != nil {
    51  		return "", err
    52  	}
    53  
    54  	// FIXME: note that this is slightly incompatible with RootFS logic
    55  	config["layer_id"] = rawJSON(layerID)
    56  	if parent != "" {
    57  		config["parent"] = rawJSON(parent)
    58  	}
    59  
    60  	configJSON, err := json.Marshal(config)
    61  	if err != nil {
    62  		return "", err
    63  	}
    64  	logrus.Debugf("CreateV1ID %s", configJSON)
    65  
    66  	return digest.FromBytes(configJSON), nil
    67  }
    68  
    69  // MakeConfigFromV1Config creates an image config from the legacy V1 config format.
    70  func MakeConfigFromV1Config(imageJSON []byte, rootfs *image.RootFS, history []image.History) ([]byte, error) {
    71  	var dver struct {
    72  		DockerVersion string `json:"docker_version"`
    73  	}
    74  
    75  	if err := json.Unmarshal(imageJSON, &dver); err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	useFallback := version.Version(dver.DockerVersion).LessThan(noFallbackMinVersion)
    80  
    81  	if useFallback {
    82  		var v1Image image.V1Image
    83  		err := json.Unmarshal(imageJSON, &v1Image)
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  		imageJSON, err = json.Marshal(v1Image)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  	}
    92  
    93  	var c map[string]*json.RawMessage
    94  	if err := json.Unmarshal(imageJSON, &c); err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	delete(c, "id")
    99  	delete(c, "parent")
   100  	delete(c, "Size") // Size is calculated from data on disk and is inconsistent
   101  	delete(c, "parent_id")
   102  	delete(c, "layer_id")
   103  	delete(c, "throwaway")
   104  
   105  	c["rootfs"] = rawJSON(rootfs)
   106  	c["history"] = rawJSON(history)
   107  
   108  	return json.Marshal(c)
   109  }
   110  
   111  // MakeV1ConfigFromConfig creates an legacy V1 image config from an Image struct
   112  func MakeV1ConfigFromConfig(img *image.Image, v1ID, parentV1ID string, throwaway bool) ([]byte, error) {
   113  	// Top-level v1compatibility string should be a modified version of the
   114  	// image config.
   115  	var configAsMap map[string]*json.RawMessage
   116  	if err := json.Unmarshal(img.RawJSON(), &configAsMap); err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	// Delete fields that didn't exist in old manifest
   121  	delete(configAsMap, "rootfs")
   122  	delete(configAsMap, "history")
   123  	configAsMap["id"] = rawJSON(v1ID)
   124  	if parentV1ID != "" {
   125  		configAsMap["parent"] = rawJSON(parentV1ID)
   126  	}
   127  	if throwaway {
   128  		configAsMap["throwaway"] = rawJSON(true)
   129  	}
   130  
   131  	return json.Marshal(configAsMap)
   132  }
   133  
   134  func rawJSON(value interface{}) *json.RawMessage {
   135  	jsonval, err := json.Marshal(value)
   136  	if err != nil {
   137  		return nil
   138  	}
   139  	return (*json.RawMessage)(&jsonval)
   140  }
   141  
   142  // ValidateID checks whether an ID string is a valid image ID.
   143  func ValidateID(id string) error {
   144  	if ok := validHex.MatchString(id); !ok {
   145  		return fmt.Errorf("image ID %q is invalid", id)
   146  	}
   147  	return nil
   148  }