imagev1.go 4.0 KB

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