mirror of
https://github.com/containers/podman.git
synced 2025-06-22 01:48:54 +08:00
Merge pull request #1637 from vrothberg/runlabel-execute-any-command
runlabel: run any command
This commit is contained in:
@ -196,7 +196,10 @@ func runlabelCmd(c *cli.Context) error {
|
||||
runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(args[2:], " "))
|
||||
}
|
||||
|
||||
cmd := shared.GenerateCommand(runLabel, imageName, c.String("name"))
|
||||
cmd, err := shared.GenerateCommand(runLabel, imageName, c.String("name"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to generate command")
|
||||
}
|
||||
env := shared.GenerateRunEnvironment(c.String("name"), imageName, opts)
|
||||
env = append(env, "PODMAN_RUNLABEL_NESTED=1")
|
||||
|
||||
|
@ -3,11 +3,39 @@ package shared
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func substituteCommand(cmd string) (string, error) {
|
||||
// If cmd is an absolute or relative path, check if the file exists.
|
||||
// Throw an error if it doesn't exist.
|
||||
if strings.Contains(cmd, "/") || strings.HasPrefix(cmd, ".") {
|
||||
res, err := filepath.Abs(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(res); !os.IsNotExist(err) {
|
||||
return res, nil
|
||||
} else if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// Replace cmd with "/proc/self/exe" if "podman" or "docker" is being
|
||||
// used. Otherwise, leave the command unchanged.
|
||||
switch cmd {
|
||||
case "podman":
|
||||
fallthrough
|
||||
case "docker":
|
||||
return "/proc/self/exe", nil
|
||||
default:
|
||||
return cmd, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateCommand takes a label (string) and converts it to an executable command
|
||||
func GenerateCommand(command, imageName, name string) []string {
|
||||
func GenerateCommand(command, imageName, name string) ([]string, error) {
|
||||
var (
|
||||
newCommand []string
|
||||
)
|
||||
@ -15,8 +43,13 @@ func GenerateCommand(command, imageName, name string) []string {
|
||||
name = imageName
|
||||
}
|
||||
cmd := strings.Split(command, " ")
|
||||
// Replace the first element of cmd with "/proc/self/exe"
|
||||
newCommand = append(newCommand, "/proc/self/exe")
|
||||
|
||||
prog, err := substituteCommand(cmd[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newCommand = append(newCommand, prog)
|
||||
|
||||
for _, arg := range cmd[1:] {
|
||||
var newArg string
|
||||
switch arg {
|
||||
@ -37,7 +70,7 @@ func GenerateCommand(command, imageName, name string) []string {
|
||||
}
|
||||
newCommand = append(newCommand, newArg)
|
||||
}
|
||||
return newCommand
|
||||
return newCommand, nil
|
||||
}
|
||||
|
||||
// GenerateRunEnvironment merges the current environment variables with optional
|
||||
|
@ -1,6 +1,10 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -16,35 +20,106 @@ var (
|
||||
func TestGenerateCommand(t *testing.T) {
|
||||
inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
||||
correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
|
||||
newCommand := GenerateCommand(inputCommand, "foo", "bar")
|
||||
newCommand, err := GenerateCommand(inputCommand, "foo", "bar")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||
}
|
||||
|
||||
func TestGenerateCommandCheckSubstitution(t *testing.T) {
|
||||
type subsTest struct {
|
||||
input string
|
||||
expected string
|
||||
shouldFail bool
|
||||
}
|
||||
|
||||
absTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestAbsolutePath")
|
||||
assert.Nil(t, err, "error creating tempfile")
|
||||
defer os.Remove(absTmpFile.Name())
|
||||
|
||||
relTmpFile, err := ioutil.TempFile("./", "podmanRunlabelTestRelativePath")
|
||||
assert.Nil(t, err, "error creating tempfile")
|
||||
defer os.Remove(relTmpFile.Name())
|
||||
relTmpCmd, err := filepath.Abs(relTmpFile.Name())
|
||||
assert.Nil(t, err, "error getting absolute path for relative tmpfile")
|
||||
|
||||
// this has a (low) potential of race conditions but no other way
|
||||
removedTmpFile, err := ioutil.TempFile("", "podmanRunlabelTestRemove")
|
||||
assert.Nil(t, err, "error creating tempfile")
|
||||
os.Remove(removedTmpFile.Name())
|
||||
|
||||
absTmpCmd := fmt.Sprintf("%s --flag1 --flag2 --args=foo", absTmpFile.Name())
|
||||
tests := []subsTest{
|
||||
{
|
||||
input: "docker run -it alpine:latest",
|
||||
expected: "/proc/self/exe run -it alpine:latest",
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
input: "podman run -it alpine:latest",
|
||||
expected: "/proc/self/exe run -it alpine:latest",
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
input: absTmpCmd,
|
||||
expected: absTmpCmd,
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
input: "./" + relTmpFile.Name(),
|
||||
expected: relTmpCmd,
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
input: "ls -la",
|
||||
expected: "ls -la",
|
||||
shouldFail: false,
|
||||
},
|
||||
{
|
||||
input: removedTmpFile.Name(),
|
||||
expected: "",
|
||||
shouldFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
newCommand, err := GenerateCommand(test.input, "foo", "bar")
|
||||
if test.shouldFail {
|
||||
assert.NotNil(t, err)
|
||||
} else {
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
assert.Equal(t, test.expected, strings.Join(newCommand, " "))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCommandPath(t *testing.T) {
|
||||
inputCommand := "/usr/bin/docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
||||
inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
||||
correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
|
||||
newCommand := GenerateCommand(inputCommand, "foo", "bar")
|
||||
newCommand, _ := GenerateCommand(inputCommand, "foo", "bar")
|
||||
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||
}
|
||||
|
||||
func TestGenerateCommandNoSetName(t *testing.T) {
|
||||
inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
||||
correctCommand := "/proc/self/exe run -it --name foo -e NAME=foo -e IMAGE=foo foo echo install"
|
||||
newCommand := GenerateCommand(inputCommand, "foo", "")
|
||||
newCommand, err := GenerateCommand(inputCommand, "foo", "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||
}
|
||||
|
||||
func TestGenerateCommandNoName(t *testing.T) {
|
||||
inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
|
||||
correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo echo install"
|
||||
newCommand := GenerateCommand(inputCommand, "foo", "")
|
||||
newCommand, err := GenerateCommand(inputCommand, "foo", "")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||
}
|
||||
|
||||
func TestGenerateCommandAlreadyPodman(t *testing.T) {
|
||||
inputCommand := "podman run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
||||
correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo install"
|
||||
newCommand := GenerateCommand(inputCommand, "foo", "bar")
|
||||
newCommand, err := GenerateCommand(inputCommand, "foo", "bar")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||
}
|
||||
|
||||
|
68
test/e2e/runlabel_test.go
Normal file
68
test/e2e/runlabel_test.go
Normal file
@ -0,0 +1,68 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var PodmanDockerfile = `
|
||||
FROM alpine:latest
|
||||
LABEL RUN podman --version`
|
||||
|
||||
var LsDockerfile = `
|
||||
FROM alpine:latest
|
||||
LABEL RUN ls -la`
|
||||
|
||||
var _ = Describe("podman container runlabel", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest PodmanTest
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanCreate(tempdir)
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.Cleanup()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
|
||||
GinkgoWriter.Write([]byte(timedResult))
|
||||
|
||||
})
|
||||
|
||||
It("podman container runlabel (podman --version)", func() {
|
||||
image := "podman-runlabel-test:podman"
|
||||
podmanTest.BuildImage(PodmanDockerfile, image, "false")
|
||||
|
||||
result := podmanTest.Podman([]string{"container", "runlabel", "RUN", image})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
|
||||
result = podmanTest.Podman([]string{"rmi", image})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("podman container runlabel (ls -la)", func() {
|
||||
image := "podman-runlabel-test:ls"
|
||||
podmanTest.BuildImage(LsDockerfile, image, "false")
|
||||
|
||||
result := podmanTest.Podman([]string{"container", "runlabel", "RUN", image})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
|
||||
result = podmanTest.Podman([]string{"rmi", image})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user