mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
specgen,run: support running container from valid manifest list
Following PR adds support for running containers from a manifest list present on localstorage. Before this PR podman only supports running containers from valid images but not from manifest list. So `podman run -it --platform <some> <manifest-list> command` should become functional now and users should be able to resolve images on the bases of provided `--platform` string. Example ``` podman manifest create test podman build --platform linux/amd64,linux/arm64 --manifest test . podman run --rm --platform linux/arm64/v8 test uname -a ``` Closes: https://github.com/containers/podman/issues/14773 Signed-off-by: Aditya R <arajan@redhat.com>
This commit is contained in:
@ -63,7 +63,7 @@ func clone(cmd *cobra.Command, args []string) error {
|
|||||||
ctrClone.Image = args[2]
|
ctrClone.Image = args[2]
|
||||||
if !cliVals.RootFS {
|
if !cliVals.RootFS {
|
||||||
rawImageName := args[0]
|
rawImageName := args[0]
|
||||||
name, err := PullImage(ctrClone.Image, ctrClone.CreateOpts)
|
name, err := PullImage(ctrClone.Image, &ctrClone.CreateOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ func create(cmd *cobra.Command, args []string) error {
|
|||||||
rawImageName := ""
|
rawImageName := ""
|
||||||
if !cliVals.RootFS {
|
if !cliVals.RootFS {
|
||||||
rawImageName = args[0]
|
rawImageName = args[0]
|
||||||
name, err := PullImage(args[0], cliVals)
|
name, err := PullImage(args[0], &cliVals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -305,7 +305,8 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
|
|||||||
return vals, nil
|
return vals, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PullImage(imageName string, cliVals entities.ContainerCreateOptions) (string, error) {
|
// Pulls image if any also parses and populates OS, Arch and Variant in specified container create options
|
||||||
|
func PullImage(imageName string, cliVals *entities.ContainerCreateOptions) (string, error) {
|
||||||
pullPolicy, err := config.ParsePullPolicy(cliVals.Pull)
|
pullPolicy, err := config.ParsePullPolicy(cliVals.Pull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -141,7 +141,7 @@ func run(cmd *cobra.Command, args []string) error {
|
|||||||
rawImageName := ""
|
rawImageName := ""
|
||||||
if !cliVals.RootFS {
|
if !cliVals.RootFS {
|
||||||
rawImageName = args[0]
|
rawImageName = args[0]
|
||||||
name, err := PullImage(args[0], cliVals)
|
name, err := PullImage(args[0], &cliVals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -192,6 +192,9 @@ func run(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.RawImageName = rawImageName
|
s.RawImageName = rawImageName
|
||||||
|
s.ImageOS = cliVals.OS
|
||||||
|
s.ImageArch = cliVals.Arch
|
||||||
|
s.ImageVariant = cliVals.Variant
|
||||||
s.Passwd = &runOpts.Passwd
|
s.Passwd = &runOpts.Passwd
|
||||||
runOpts.Spec = s
|
runOpts.Spec = s
|
||||||
|
|
||||||
|
@ -38,10 +38,19 @@ func getImageFromSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Need to look up image.
|
// Need to look up image.
|
||||||
image, resolvedName, err := r.LibimageRuntime().LookupImage(s.Image, nil)
|
lookupOptions := &libimage.LookupImageOptions{ManifestList: true}
|
||||||
|
image, resolvedName, err := r.LibimageRuntime().LookupImage(s.Image, lookupOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", nil, err
|
return nil, "", nil, err
|
||||||
}
|
}
|
||||||
|
manifestList, err := image.ToManifestList()
|
||||||
|
// only process if manifest list found otherwise expect it to be regular image
|
||||||
|
if err == nil {
|
||||||
|
image, err = manifestList.LookupInstance(ctx, s.ImageArch, s.ImageOS, s.ImageVariant)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
s.SetImage(image, resolvedName)
|
s.SetImage(image, resolvedName)
|
||||||
inspectData, err := image.Inspect(ctx, nil)
|
inspectData, err := image.Inspect(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -103,6 +103,12 @@ type ContainerBasicConfig struct {
|
|||||||
// RawImageName is the user-specified and unprocessed input referring
|
// RawImageName is the user-specified and unprocessed input referring
|
||||||
// to a local or a remote image.
|
// to a local or a remote image.
|
||||||
RawImageName string `json:"raw_image_name,omitempty"`
|
RawImageName string `json:"raw_image_name,omitempty"`
|
||||||
|
// ImageOS is the user-specified image OS
|
||||||
|
ImageOS string `json:"image_os,omitempty"`
|
||||||
|
// ImageArch is the user-specified image architecture
|
||||||
|
ImageArch string `json:"image_arch,omitempty"`
|
||||||
|
// ImageVariant is the user-specified image variant
|
||||||
|
ImageVariant string `json:"image_variant,omitempty"`
|
||||||
// RestartPolicy is the container's restart policy - an action which
|
// RestartPolicy is the container's restart policy - an action which
|
||||||
// will be taken when the container exits.
|
// will be taken when the container exits.
|
||||||
// If not given, the default policy, which does nothing, will be used.
|
// If not given, the default policy, which does nothing, will be used.
|
||||||
|
1
test/e2e/build/Containerfile.with-platform
Normal file
1
test/e2e/build/Containerfile.with-platform
Normal file
@ -0,0 +1 @@
|
|||||||
|
FROM --platform=$TARGETPLATFORM alpine
|
@ -73,6 +73,28 @@ var _ = Describe("Podman run", func() {
|
|||||||
Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
|
Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman run from manifest list", func() {
|
||||||
|
session := podmanTest.Podman([]string{"manifest", "create", "localhost/test:latest"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"build", "-f", "build/Containerfile.with-platform", "--platform", "linux/amd64,linux/arm64", "--manifest", "localhost/test:latest"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
session = podmanTest.Podman([]string{"run", "--platform", "linux/arm64", "localhost/test", "uname", "-a"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
exitCode := session.ExitCode()
|
||||||
|
// CI could either support requested platform or not, if it supports then output should contain `aarch64`
|
||||||
|
// if not run should fail with a very specific error i.e `Exec format error` anything other than this should
|
||||||
|
// be marked as failure of test.
|
||||||
|
if exitCode == 0 {
|
||||||
|
Expect(session.OutputToString()).To(ContainSubstring("aarch64"))
|
||||||
|
} else {
|
||||||
|
Expect(session.ErrorToString()).To(ContainSubstring("Exec format error"))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
It("podman run a container based on a complex local image name", func() {
|
It("podman run a container based on a complex local image name", func() {
|
||||||
imageName := strings.TrimPrefix(nginx, "quay.io/")
|
imageName := strings.TrimPrefix(nginx, "quay.io/")
|
||||||
session := podmanTest.Podman([]string{"run", imageName, "ls"})
|
session := podmanTest.Podman([]string{"run", imageName, "ls"})
|
||||||
|
Reference in New Issue
Block a user