github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/image/v1/imagev1.go (about) 1 package v1 // import "github.com/demonoid81/moby/image/v1" 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "strings" 7 8 "github.com/demonoid81/moby/api/types/versions" 9 "github.com/demonoid81/moby/image" 10 "github.com/demonoid81/moby/layer" 11 "github.com/demonoid81/moby/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 }