diff --git a/go.mod b/go.mod index 8e6e6bb553..4c4469a16a 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,8 @@ require ( github.com/alessio/shellescape v1.4.1 github.com/evanphx/json-patch/v5 v5.6.0 github.com/mattn/go-isatty v0.0.14 + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml v1.9.4 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.4.0 diff --git a/go.sum b/go.sum index 62632efb7f..22e8254274 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/pkg/build/nodeimage/internal/container/docker/archive.go b/pkg/build/nodeimage/internal/container/docker/archive.go index 11013df391..307d613e65 100644 --- a/pkg/build/nodeimage/internal/container/docker/archive.go +++ b/pkg/build/nodeimage/internal/container/docker/archive.go @@ -27,6 +27,7 @@ import ( "os" "strings" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "sigs.k8s.io/kind/pkg/errors" ) @@ -36,6 +37,7 @@ import ( // https://github.com/moby/moby/blob/master/image/spec/v1.md // https://github.com/moby/moby/blob/master/image/spec/v1.1.md // https://github.com/moby/moby/blob/master/image/spec/v1.2.md +// https://github.com/opencontainers/image-spec/blob/v1.0.0/spec.md func GetArchiveTags(path string) ([]string, error) { // open the archive and find the repositories entry f, err := os.Open(path) @@ -44,7 +46,12 @@ func GetArchiveTags(path string) ([]string, error) { } defer f.Close() tr := tar.NewReader(f) - var hdr *tar.Header + var ( + hdr *tar.Header + ociLayout ocispec.ImageLayout + indexBytes []byte + repoTags archiveRepositories + ) for { hdr, err = tr.Next() if err == io.EOF { @@ -54,19 +61,49 @@ func GetArchiveTags(path string) ([]string, error) { return nil, err } if hdr.Name == "repositories" { + if err := untarJSON(tr, &repoTags); err != nil { + return nil, err + } + break + } else if hdr.Name == ocispec.ImageLayoutFile { + if err := untarJSON(tr, &ociLayout); err != nil { + return nil, err + } + } else if hdr.Name == "index.json" { + indexBytes, err = ioutil.ReadAll(tr) + if err != nil { + return nil, err + } + } + if ociLayout.Version != "" && len(indexBytes) > 0 { break } } - // read and parse the tags - b, err := ioutil.ReadAll(tr) - if err != nil { - return nil, err - } - // parse - repoTags, err := parseRepositories(b) - if err != nil { - return nil, err + + if ociLayout.Version != "" { + if ociLayout.Version != ocispec.ImageLayoutVersion { + return nil, fmt.Errorf("unsupported OCI Version: %s", ociLayout.Version) + } + + var imageIndex ocispec.Index + if err := json.Unmarshal(indexBytes, &imageIndex); err != nil { + return nil, err + } + + res := []string{} + for _, manifest := range imageIndex.Manifests { + if imageName, ok := manifest.Annotations["io.containerd.image.name"]; ok { + res = append(res, imageName) + } + } + + if len(res) == 0 { + return nil, errors.New("could not find image tags in image metadata") + } + + return res, nil } + // convert to tags in the docker CLI sense res := []string{} for repo, tags := range repoTags { @@ -215,3 +252,12 @@ func parseRepositories(data []byte) (archiveRepositories, error) { } return repoTags, nil } + +func untarJSON(reader io.Reader, i interface{}) error { + b, err := ioutil.ReadAll(reader) + if err != nil { + return err + } + + return json.Unmarshal(b, i) +}