mirror of
https://github.com/containers/podman.git
synced 2025-06-22 18:08:11 +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:], " "))
|
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 := shared.GenerateRunEnvironment(c.String("name"), imageName, opts)
|
||||||
env = append(env, "PODMAN_RUNLABEL_NESTED=1")
|
env = append(env, "PODMAN_RUNLABEL_NESTED=1")
|
||||||
|
|
||||||
|
@ -3,11 +3,39 @@ package shared
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"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
|
// 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 (
|
var (
|
||||||
newCommand []string
|
newCommand []string
|
||||||
)
|
)
|
||||||
@ -15,8 +43,13 @@ func GenerateCommand(command, imageName, name string) []string {
|
|||||||
name = imageName
|
name = imageName
|
||||||
}
|
}
|
||||||
cmd := strings.Split(command, " ")
|
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:] {
|
for _, arg := range cmd[1:] {
|
||||||
var newArg string
|
var newArg string
|
||||||
switch arg {
|
switch arg {
|
||||||
@ -37,7 +70,7 @@ func GenerateCommand(command, imageName, name string) []string {
|
|||||||
}
|
}
|
||||||
newCommand = append(newCommand, newArg)
|
newCommand = append(newCommand, newArg)
|
||||||
}
|
}
|
||||||
return newCommand
|
return newCommand, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateRunEnvironment merges the current environment variables with optional
|
// GenerateRunEnvironment merges the current environment variables with optional
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package shared
|
package shared
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -16,35 +20,106 @@ var (
|
|||||||
func TestGenerateCommand(t *testing.T) {
|
func TestGenerateCommand(t *testing.T) {
|
||||||
inputCommand := "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"
|
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, " "))
|
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) {
|
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"
|
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, " "))
|
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateCommandNoSetName(t *testing.T) {
|
func TestGenerateCommandNoSetName(t *testing.T) {
|
||||||
inputCommand := "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 foo -e NAME=foo -e IMAGE=foo foo 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, " "))
|
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateCommandNoName(t *testing.T) {
|
func TestGenerateCommandNoName(t *testing.T) {
|
||||||
inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
|
inputCommand := "docker run -it -e IMAGE=IMAGE IMAGE echo install"
|
||||||
correctCommand := "/proc/self/exe run -it -e IMAGE=foo foo 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, " "))
|
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateCommandAlreadyPodman(t *testing.T) {
|
func TestGenerateCommandAlreadyPodman(t *testing.T) {
|
||||||
inputCommand := "podman run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo install"
|
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"
|
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, " "))
|
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