github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/image/v1/imagev1.go (about)

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