Files
moby/internal/testutils/specialimage/random.go
Paweł Gronowski 59169d0f97 image/inspect: Add platform selection
`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>
2025-04-03 13:57:51 +02:00

110 lines
2.6 KiB
Go

package specialimage
import (
"encoding/json"
"math/rand"
"os"
"path/filepath"
"strconv"
"github.com/distribution/reference"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
func RandomSinglePlatform(dir string, platform ocispec.Platform, source rand.Source) (*ocispec.Index, error) {
r := rand.New(source) //nolint:gosec // Ignore G404: Use of weak random number generator (math/rand instead of crypto/rand)
imageRef := "random-" + strconv.FormatInt(r.Int63(), 10) + ":latest"
layerCount := r.Intn(8)
var layers []ocispec.Descriptor
for i := 0; i < layerCount; i++ {
layerDesc, err := writeLayerWithOneFile(dir, "layer-"+strconv.Itoa(i), []byte(strconv.Itoa(i)))
if err != nil {
return nil, err
}
layers = append(layers, layerDesc)
}
configDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, 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: layersToDigests(layers),
},
})
if err != nil {
return nil, err
}
manifest := ocispec.Manifest{
MediaType: ocispec.MediaTypeImageManifest,
Config: configDesc,
Layers: layers,
}
legacyManifests := []manifestItem{
{
Config: blobPath(configDesc),
RepoTags: []string{imageRef},
Layers: blobPaths(layers),
},
}
ref, err := reference.ParseNormalizedNamed(imageRef)
if err != nil {
return nil, err
}
return singlePlatformImage(dir, ref, manifest, legacyManifests)
}
func layersToDigests(layers []ocispec.Descriptor) []digest.Digest {
var digests []digest.Digest
for _, l := range layers {
digests = append(digests, l.Digest)
}
return digests
}
func blobPaths(descriptors []ocispec.Descriptor) []string {
var paths []string
for _, d := range descriptors {
paths = append(paths, blobPath(d))
}
return paths
}
func readJson(path string, v any) error {
content, err := os.ReadFile(path)
if err != nil {
return err
}
return json.Unmarshal(content, v)
}
func LegacyManifest(dir string, imageRef string, mfstDesc ocispec.Descriptor) error {
legacyManifests := []manifestItem{}
var mfst ocispec.Manifest
if err := readJson(filepath.Join(dir, blobPath(mfstDesc)), &mfst); err != nil {
return err
}
legacyManifests = append(legacyManifests, manifestItem{
Config: blobPath(mfst.Config),
RepoTags: []string{imageRef},
Layers: blobPaths(mfst.Layers),
})
if err := writeJson(legacyManifests, filepath.Join(dir, "manifest.json")); err != nil {
return err
}
return nil
}