github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/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.Slice(), " "), 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 inconsitent 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 '%s' is invalid ", id) 146 } 147 return nil 148 }