mirror of
https://github.com/containers/podman.git
synced 2025-12-12 17:57:31 +08:00
When an image name has no reponames, you should still be able to run it by ID. When doing so, imageName needs to be set to "" so we don't hit an index out of range error Resolves: #587 Signed-off-by: baude <bbaude@redhat.com> Closes: #593 Approved by: mheon
179 lines
4.8 KiB
Go
179 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/projectatomic/libpod/libpod"
|
|
"github.com/projectatomic/libpod/libpod/image"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli"
|
|
"os"
|
|
)
|
|
|
|
var runDescription = "Runs a command in a new container from the given image"
|
|
|
|
var runFlags []cli.Flag = append(createFlags, cli.BoolTFlag{
|
|
Name: "sig-proxy",
|
|
Usage: "proxy received signals to the process (default true)",
|
|
})
|
|
|
|
var runCommand = cli.Command{
|
|
Name: "run",
|
|
Usage: "run a command in a new container",
|
|
Description: runDescription,
|
|
Flags: runFlags,
|
|
Action: runCmd,
|
|
ArgsUsage: "IMAGE [COMMAND [ARG...]]",
|
|
SkipArgReorder: true,
|
|
UseShortOptionHandling: true,
|
|
}
|
|
|
|
func runCmd(c *cli.Context) error {
|
|
var imageName string
|
|
if err := validateFlags(c, createFlags); err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.String("cidfile") != "" {
|
|
if _, err := os.Stat(c.String("cidfile")); err == nil {
|
|
return errors.Errorf("container id file exists. ensure another container is not using it or delete %s", c.String("cidfile"))
|
|
}
|
|
if err := libpod.WriteFile("", c.String("cidfile")); err != nil {
|
|
return errors.Wrapf(err, "unable to write cidfile %s", c.String("cidfile"))
|
|
}
|
|
}
|
|
|
|
runtime, err := getRuntime(c)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error creating libpod runtime")
|
|
}
|
|
defer runtime.Shutdown(false)
|
|
if len(c.Args()) < 1 {
|
|
return errors.Errorf("image name or ID is required")
|
|
}
|
|
|
|
rtc := runtime.GetConfig()
|
|
newImage, err := runtime.ImageRuntime().New(c.Args()[0], rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{})
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to find image")
|
|
}
|
|
|
|
data, err := newImage.Inspect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(newImage.Names()) < 1 {
|
|
imageName = newImage.ID()
|
|
} else {
|
|
imageName = newImage.Names()[0]
|
|
}
|
|
createConfig, err := parseCreateOpts(c, runtime, imageName, data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
useImageVolumes := createConfig.ImageVolumeType == "bind"
|
|
|
|
runtimeSpec, err := createConfigToOCISpec(createConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
options, err := createConfig.GetContainerCreateOptions()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to parse new container options")
|
|
}
|
|
|
|
// Gather up the options for NewContainer which consist of With... funcs
|
|
options = append(options, libpod.WithRootFSFromImage(createConfig.ImageID, createConfig.Image, useImageVolumes))
|
|
options = append(options, libpod.WithSELinuxLabels(createConfig.ProcessLabel, createConfig.MountLabel))
|
|
options = append(options, libpod.WithConmonPidFile(createConfig.ConmonPidFile))
|
|
options = append(options, libpod.WithLabels(createConfig.Labels))
|
|
options = append(options, libpod.WithUser(createConfig.User))
|
|
options = append(options, libpod.WithShmDir(createConfig.ShmDir))
|
|
options = append(options, libpod.WithShmSize(createConfig.Resources.ShmSize))
|
|
|
|
// Default used if not overridden on command line
|
|
|
|
if createConfig.CgroupParent != "" {
|
|
options = append(options, libpod.WithCgroupParent(createConfig.CgroupParent))
|
|
}
|
|
|
|
ctr, err := runtime.NewContainer(runtimeSpec, options...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if logrus.GetLevel() == logrus.DebugLevel {
|
|
logrus.Debugf("New container created %q", ctr.ID())
|
|
|
|
p, _ := ctr.CGroupPath()("")
|
|
logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), p)
|
|
}
|
|
|
|
createConfigJSON, err := json.Marshal(createConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
|
|
return err
|
|
}
|
|
|
|
if c.String("cidfile") != "" {
|
|
if err := libpod.WriteFile(ctr.ID(), c.String("cidfile")); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
|
|
// Handle detached start
|
|
if createConfig.Detach {
|
|
if err := ctr.Start(); err != nil {
|
|
// This means the command did not exist
|
|
exitCode = 127
|
|
if strings.Index(err.Error(), "permission denied") > -1 {
|
|
exitCode = 126
|
|
}
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("%s\n", ctr.ID())
|
|
exitCode = 0
|
|
return nil
|
|
}
|
|
|
|
// TODO: that "false" should probably be linked to -i
|
|
// Handle this when we split streams to allow attaching just stdin/out/err
|
|
attachChan, err := ctr.StartAndAttach(false, c.String("detach-keys"))
|
|
if err != nil {
|
|
// This means the command did not exist
|
|
exitCode = 127
|
|
if strings.Index(err.Error(), "permission denied") > -1 {
|
|
exitCode = 126
|
|
}
|
|
return err
|
|
}
|
|
|
|
if c.BoolT("sig-proxy") {
|
|
ProxySignals(ctr)
|
|
}
|
|
|
|
// Wait for attach to complete
|
|
err = <-attachChan
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
|
|
}
|
|
|
|
if ecode, err := ctr.ExitCode(); err != nil {
|
|
logrus.Errorf("unable to get exit code of container %s: %q", ctr.ID(), err)
|
|
} else {
|
|
exitCode = int(ecode)
|
|
}
|
|
|
|
if createConfig.Rm {
|
|
return runtime.RemoveContainer(ctr, true)
|
|
}
|
|
return ctr.Cleanup()
|
|
}
|