mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
`GET /image/{name}/json` now supports `platform` parameter allowing to
specify which platform variant of a multi-platform image to inspect.
For servers that do not use containerd image store integration, this
option will cause an error if the requested platform doesn't match the
image's actual platform
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
114 lines
3.0 KiB
Go
114 lines
3.0 KiB
Go
package specialimage
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/containerd/platforms"
|
|
"github.com/distribution/reference"
|
|
"github.com/opencontainers/go-digest"
|
|
"github.com/opencontainers/image-spec/specs-go"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
)
|
|
|
|
func TwoPlatform(dir string) (*ocispec.Index, error) {
|
|
const imageRef = "twoplatform:latest"
|
|
ref, err := reference.ParseNormalizedNamed(imageRef)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
manifest1Desc, _, err := oneLayerPlatformManifest(dir, platforms.MustParse("linux/amd64"), FileInLayer{Path: "bash", Content: []byte("layer1")})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
manifest2Desc, _, err := oneLayerPlatformManifest(dir, platforms.MustParse("linux/arm64"), FileInLayer{Path: "bash", Content: []byte("layer2")})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return multiPlatformImage(dir, ref, ocispec.Index{
|
|
Versioned: specs.Versioned{SchemaVersion: 2},
|
|
MediaType: ocispec.MediaTypeImageIndex,
|
|
Manifests: []ocispec.Descriptor{manifest1Desc, manifest2Desc},
|
|
})
|
|
}
|
|
|
|
type FileInLayer struct {
|
|
Path string
|
|
Content []byte
|
|
}
|
|
|
|
func oneLayerPlatformManifest(dir string, platform ocispec.Platform, f FileInLayer) (ocispec.Descriptor, manifestItem, error) {
|
|
layerDesc, err := writeLayerWithOneFile(dir, f.Path, f.Content)
|
|
if err != nil {
|
|
return ocispec.Descriptor{}, manifestItem{}, err
|
|
}
|
|
|
|
img := ocispec.Image{
|
|
Platform: platform,
|
|
Config: ocispec.ImageConfig{
|
|
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
|
},
|
|
RootFS: ocispec.RootFS{
|
|
Type: "layers",
|
|
DiffIDs: []digest.Digest{layerDesc.Digest},
|
|
},
|
|
}
|
|
|
|
configDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, img)
|
|
if err != nil {
|
|
return ocispec.Descriptor{}, manifestItem{}, err
|
|
}
|
|
|
|
manifestDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageManifest, ocispec.Manifest{
|
|
MediaType: ocispec.MediaTypeImageManifest,
|
|
Config: configDesc,
|
|
Layers: []ocispec.Descriptor{layerDesc},
|
|
})
|
|
if err != nil {
|
|
return ocispec.Descriptor{}, manifestItem{}, err
|
|
}
|
|
manifestDesc.Platform = &platform
|
|
|
|
return manifestDesc, manifestItem{
|
|
Config: blobPath(configDesc),
|
|
Layers: []string{blobPath(layerDesc)},
|
|
}, nil
|
|
}
|
|
|
|
func multiPlatformImage(dir string, ref reference.Named, target ocispec.Index) (*ocispec.Index, error) {
|
|
targetDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageIndex, target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ref != nil {
|
|
targetDesc.Annotations = map[string]string{
|
|
"io.containerd.image.name": ref.String(),
|
|
}
|
|
|
|
if tagged, ok := ref.(reference.Tagged); ok {
|
|
targetDesc.Annotations[ocispec.AnnotationRefName] = tagged.Tag()
|
|
}
|
|
}
|
|
|
|
index := ocispec.Index{
|
|
Versioned: specs.Versioned{SchemaVersion: 2},
|
|
MediaType: ocispec.MediaTypeImageIndex,
|
|
Manifests: []ocispec.Descriptor{targetDesc},
|
|
}
|
|
|
|
if err := writeJson(index, filepath.Join(dir, "index.json")); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = os.WriteFile(filepath.Join(dir, "oci-layout"), []byte(`{"imageLayoutVersion": "1.0.0"}`), 0o644)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &index, nil
|
|
}
|