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