helpers.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package libdocker
  14. import (
  15. "strings"
  16. "time"
  17. dockerref "github.com/docker/distribution/reference"
  18. dockertypes "github.com/docker/docker/api/types"
  19. godigest "github.com/opencontainers/go-digest"
  20. "k8s.io/klog"
  21. )
  22. // ParseDockerTimestamp parses the timestamp returned by Interface from string to time.Time
  23. func ParseDockerTimestamp(s string) (time.Time, error) {
  24. // Timestamp returned by Docker is in time.RFC3339Nano format.
  25. return time.Parse(time.RFC3339Nano, s)
  26. }
  27. // matchImageTagOrSHA checks if the given image specifier is a valid image ref,
  28. // and that it matches the given image. It should fail on things like image IDs
  29. // (config digests) and other digest-only references, but succeed on image names
  30. // (`foo`), tag references (`foo:bar`), and manifest digest references
  31. // (`foo@sha256:xyz`).
  32. func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool {
  33. // The image string follows the grammar specified here
  34. // https://github.com/docker/distribution/blob/master/reference/reference.go#L4
  35. named, err := dockerref.ParseNormalizedNamed(image)
  36. if err != nil {
  37. klog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
  38. return false
  39. }
  40. _, isTagged := named.(dockerref.Tagged)
  41. digest, isDigested := named.(dockerref.Digested)
  42. if !isTagged && !isDigested {
  43. // No Tag or SHA specified, so just return what we have
  44. return true
  45. }
  46. if isTagged {
  47. // Check the RepoTags for a match.
  48. for _, tag := range inspected.RepoTags {
  49. // An image name (without the tag/digest) can be [hostname '/'] component ['/' component]*
  50. // Because either the RepoTag or the name *may* contain the
  51. // hostname or not, we only check for the suffix match.
  52. if strings.HasSuffix(image, tag) || strings.HasSuffix(tag, image) {
  53. return true
  54. } else {
  55. // TODO: We need to remove this hack when project atomic based
  56. // docker distro(s) like centos/fedora/rhel image fix problems on
  57. // their end.
  58. // Say the tag is "docker.io/busybox:latest"
  59. // and the image is "docker.io/library/busybox:latest"
  60. t, err := dockerref.ParseNormalizedNamed(tag)
  61. if err != nil {
  62. continue
  63. }
  64. // the parsed/normalized tag will look like
  65. // reference.taggedReference {
  66. // namedRepository: reference.repository {
  67. // domain: "docker.io",
  68. // path: "library/busybox"
  69. // },
  70. // tag: "latest"
  71. // }
  72. // If it does not have tags then we bail out
  73. t2, ok := t.(dockerref.Tagged)
  74. if !ok {
  75. continue
  76. }
  77. // normalized tag would look like "docker.io/library/busybox:latest"
  78. // note the library get added in the string
  79. normalizedTag := t2.String()
  80. if normalizedTag == "" {
  81. continue
  82. }
  83. if strings.HasSuffix(image, normalizedTag) || strings.HasSuffix(normalizedTag, image) {
  84. return true
  85. }
  86. }
  87. }
  88. }
  89. if isDigested {
  90. for _, repoDigest := range inspected.RepoDigests {
  91. named, err := dockerref.ParseNormalizedNamed(repoDigest)
  92. if err != nil {
  93. klog.V(4).Infof("couldn't parse image RepoDigest reference %q: %v", repoDigest, err)
  94. continue
  95. }
  96. if d, isDigested := named.(dockerref.Digested); isDigested {
  97. if digest.Digest().Algorithm().String() == d.Digest().Algorithm().String() &&
  98. digest.Digest().Hex() == d.Digest().Hex() {
  99. return true
  100. }
  101. }
  102. }
  103. // process the ID as a digest
  104. id, err := godigest.Parse(inspected.ID)
  105. if err != nil {
  106. klog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
  107. return false
  108. }
  109. if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
  110. return true
  111. }
  112. }
  113. klog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image)
  114. return false
  115. }
  116. // matchImageIDOnly checks that the given image specifier is a digest-only
  117. // reference, and that it matches the given image.
  118. func matchImageIDOnly(inspected dockertypes.ImageInspect, image string) bool {
  119. // If the image ref is literally equal to the inspected image's ID,
  120. // just return true here (this might be the case for Docker 1.9,
  121. // where we won't have a digest for the ID)
  122. if inspected.ID == image {
  123. return true
  124. }
  125. // Otherwise, we should try actual parsing to be more correct
  126. ref, err := dockerref.Parse(image)
  127. if err != nil {
  128. klog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
  129. return false
  130. }
  131. digest, isDigested := ref.(dockerref.Digested)
  132. if !isDigested {
  133. klog.V(4).Infof("the image reference %q was not a digest reference", image)
  134. return false
  135. }
  136. id, err := godigest.Parse(inspected.ID)
  137. if err != nil {
  138. klog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
  139. return false
  140. }
  141. if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
  142. return true
  143. }
  144. klog.V(4).Infof("The reference %s does not directly refer to the given image's ID (%q)", image, inspected.ID)
  145. return false
  146. }