Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add variable for global flags to runlabel #2905

Merged
merged 1 commit into from May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/podman/runlabel.go
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -145,7 +146,8 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
return errors.Errorf("%s does not have a label of %s", runlabelImage, label)
}

cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.Name, opts, extraArgs)
globalOpts := util.GetGlobalOpts(c)
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.Name, opts, extraArgs, globalOpts)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/podman/shared/container.go
Expand Up @@ -883,7 +883,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim
}

// GenerateRunlabelCommand generates the command that will eventually be execucted by podman
func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string) ([]string, []string, error) {
func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]string, extraArgs []string, globalOpts string) ([]string, []string, error) {
// If no name is provided, we use the image's basename instead
if name == "" {
baseName, err := image.GetImageBaseName(imageName)
Expand All @@ -896,7 +896,7 @@ func GenerateRunlabelCommand(runLabel, imageName, name string, opts map[string]s
if len(extraArgs) > 0 {
runLabel = fmt.Sprintf("%s %s", runLabel, strings.Join(extraArgs, " "))
}
cmd, err := GenerateCommand(runLabel, imageName, name)
cmd, err := GenerateCommand(runLabel, imageName, name, globalOpts)
if err != nil {
return nil, nil, errors.Wrapf(err, "unable to generate command")
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/podman/shared/funcs.go
Expand Up @@ -41,7 +41,7 @@ func substituteCommand(cmd string) (string, error) {
}

// GenerateCommand takes a label (string) and converts it to an executable command
func GenerateCommand(command, imageName, name string) ([]string, error) {
func GenerateCommand(command, imageName, name, globalOpts string) ([]string, error) {
var (
newCommand []string
)
Expand Down Expand Up @@ -79,6 +79,8 @@ func GenerateCommand(command, imageName, name string) ([]string, error) {
newArg = fmt.Sprintf("NAME=%s", name)
case "$NAME":
newArg = name
case "$GLOBAL_OPTS":
newArg = globalOpts
default:
newArg = arg
}
Expand Down
12 changes: 6 additions & 6 deletions cmd/podman/shared/funcs_test.go
Expand Up @@ -20,7 +20,7 @@ var (
func TestGenerateCommand(t *testing.T) {
inputCommand := "docker run -it --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE echo \"hello world\""
correctCommand := "/proc/self/exe run -it --name bar -e NAME=bar -e IMAGE=foo foo echo hello world"
newCommand, err := GenerateCommand(inputCommand, "foo", "bar")
newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
assert.Nil(t, err)
assert.Equal(t, "hello world", newCommand[11])
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
Expand Down Expand Up @@ -83,7 +83,7 @@ func TestGenerateCommandCheckSubstitution(t *testing.T) {
}

for _, test := range tests {
newCommand, err := GenerateCommand(test.input, "foo", "bar")
newCommand, err := GenerateCommand(test.input, "foo", "bar", "")
if test.shouldFail {
assert.NotNil(t, err)
} else {
Expand All @@ -96,30 +96,30 @@ func TestGenerateCommandCheckSubstitution(t *testing.T) {
func TestGenerateCommandPath(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, _ := 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, err := 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, err := 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, err := GenerateCommand(inputCommand, "foo", "bar")
newCommand, err := GenerateCommand(inputCommand, "foo", "bar", "")
assert.Nil(t, err)
assert.Equal(t, correctCommand, strings.Join(newCommand, " "))
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/util/utils.go
Expand Up @@ -10,10 +10,12 @@ import (

"github.com/BurntSushi/toml"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"golang.org/x/crypto/ssh/terminal"
)

Expand Down Expand Up @@ -252,3 +254,32 @@ func ParseInputTime(inputTime string) (time.Time, error) {
}
return time.Now().Add(-duration), nil
}

// GetGlobalOpts checks all global flags and generates the command string
func GetGlobalOpts(c *cliconfig.RunlabelValues) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can somehow pull the names of the global flags straight out of Cobra - @baude you know if there's a way to do this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found FlagSet.VisitAll() for all flags, not just for global flags...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. This could be painful if we add more global flags, but no helping that, I suppose.

globalFlags := map[string]bool{
"cgroup-manager": true, "cni-config-dir": true, "conmon": true, "default-mounts-file": true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate PR, but could you move this to main_local.go
Add one line after each global flag gets added

	rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CGroupManager, "cgroup-manager", "", "Cgroup manager to use (cgroupfs or systemd, default systemd)")
        globalFlags["cgroup-manager"]=true
	rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
        globalFlags["cpu-profile"]=true

That way if a user adds a global flag, it is much more likely they will do the right thing.

"hooks-dir": true, "namespace": true, "root": true, "runroot": true,
"runtime": true, "storage-driver": true, "storage-opt": true, "syslog": true,
"trace": true, "network-cmd-path": true, "config": true, "cpu-profile": true,
"log-level": true, "tmpdir": true}
const stringSliceType string = "stringSlice"

var optsCommand []string
c.PodmanCommand.Command.Flags().VisitAll(func(f *pflag.Flag) {
if !f.Changed {
return
}
if _, exist := globalFlags[f.Name]; exist {
if f.Value.Type() == stringSliceType {
flagValue := strings.TrimSuffix(strings.TrimPrefix(f.Value.String(), "["), "]")
for _, value := range strings.Split(flagValue, ",") {
optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, value))
}
} else {
optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, f.Value.String()))
}
}
})
return strings.Join(optsCommand, " ")
}
2 changes: 1 addition & 1 deletion pkg/varlinkapi/images.go
Expand Up @@ -728,7 +728,7 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label))
}

cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs)
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs, "")
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
Expand Down
19 changes: 19 additions & 0 deletions test/e2e/runlabel_test.go
Expand Up @@ -18,6 +18,11 @@ var LsDockerfile = `
FROM alpine:latest
LABEL RUN ls -la`

var GlobalDockerfile = `
FROM alpine:latest
LABEL RUN echo \$GLOBAL_OPTS
`

var _ = Describe("podman container runlabel", func() {
var (
tempdir string
Expand Down Expand Up @@ -78,4 +83,18 @@ var _ = Describe("podman container runlabel", func() {
Expect(result.ExitCode()).ToNot(Equal(0))

})

It("podman container runlabel global options", func() {
image := "podman-global-test:ls"
podmanTest.BuildImage(GlobalDockerfile, image, "false")
result := podmanTest.Podman([]string{"--syslog", "--log-level", "debug", "container", "runlabel", "RUN", image})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))

Expect(result.OutputToString()).To(ContainSubstring("--syslog true"))
Expect(result.OutputToString()).To(ContainSubstring("--log-level debug"))
result = podmanTest.Podman([]string{"rmi", image})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
})
})