github.com/moby/docker@v26.1.3+incompatible/internal/testutils/specialimage/twoplatform.go (about)

     1  package specialimage
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/containerd/containerd/platforms"
     8  	"github.com/distribution/reference"
     9  	"github.com/opencontainers/go-digest"
    10  	"github.com/opencontainers/image-spec/specs-go"
    11  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    12  )
    13  
    14  func TwoPlatform(dir string) (*ocispec.Index, error) {
    15  	const imageRef = "twoplatform:latest"
    16  
    17  	layer1Desc, err := writeLayerWithOneFile(dir, "bash", []byte("layer1"))
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  	layer2Desc, err := writeLayerWithOneFile(dir, "bash", []byte("layer2"))
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  
    26  	config1Desc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, ocispec.Image{
    27  		Platform: platforms.MustParse("linux/amd64"),
    28  		Config: ocispec.ImageConfig{
    29  			Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
    30  		},
    31  		RootFS: ocispec.RootFS{
    32  			Type:    "layers",
    33  			DiffIDs: []digest.Digest{layer1Desc.Digest},
    34  		},
    35  	})
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	manifest1Desc, err := writeJsonBlob(dir, ocispec.MediaTypeImageManifest, ocispec.Manifest{
    41  		MediaType: ocispec.MediaTypeImageManifest,
    42  		Config:    config1Desc,
    43  		Layers:    []ocispec.Descriptor{layer1Desc},
    44  	})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	config2Desc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, ocispec.Image{
    50  		Platform: platforms.MustParse("linux/arm64"),
    51  		Config: ocispec.ImageConfig{
    52  			Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
    53  		},
    54  		RootFS: ocispec.RootFS{
    55  			Type:    "layers",
    56  			DiffIDs: []digest.Digest{layer1Desc.Digest},
    57  		},
    58  	})
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	manifest2Desc, err := writeJsonBlob(dir, ocispec.MediaTypeImageManifest, ocispec.Manifest{
    64  		MediaType: ocispec.MediaTypeImageManifest,
    65  		Config:    config2Desc,
    66  		Layers:    []ocispec.Descriptor{layer2Desc},
    67  	})
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	index := ocispec.Index{
    73  		Versioned: specs.Versioned{SchemaVersion: 2},
    74  		MediaType: ocispec.MediaTypeImageIndex,
    75  		Manifests: []ocispec.Descriptor{manifest1Desc, manifest2Desc},
    76  	}
    77  
    78  	ref, err := reference.ParseNormalizedNamed(imageRef)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return multiPlatformImage(dir, ref, index)
    83  }
    84  
    85  func multiPlatformImage(dir string, ref reference.Named, target ocispec.Index) (*ocispec.Index, error) {
    86  	targetDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageIndex, target)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	if ref != nil {
    92  		targetDesc.Annotations = map[string]string{
    93  			"io.containerd.image.name": ref.String(),
    94  		}
    95  
    96  		if tagged, ok := ref.(reference.Tagged); ok {
    97  			targetDesc.Annotations[ocispec.AnnotationRefName] = tagged.Tag()
    98  		}
    99  	}
   100  
   101  	index := ocispec.Index{
   102  		Versioned: specs.Versioned{SchemaVersion: 2},
   103  		MediaType: ocispec.MediaTypeImageIndex,
   104  		Manifests: []ocispec.Descriptor{targetDesc},
   105  	}
   106  
   107  	if err := writeJson(index, filepath.Join(dir, "index.json")); err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	err = os.WriteFile(filepath.Join(dir, "oci-layout"), []byte(`{"imageLayoutVersion": "1.0.0"}`), 0o644)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	return &index, nil
   117  }