summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorJhon Honce <jhonce@redhat.com>2020-04-14 11:00:40 -0700
committerJhon Honce <jhonce@redhat.com>2020-04-14 14:48:37 -0700
commitd51727642603ba160a7898ee4597d0f071cdea44 (patch)
treec2b3a369924f29ddf1762d32941dd10b38da2b9d /cmd
parent0d01f09bf4103538a6011019b690e5aa11c377db (diff)
downloadpodman-d51727642603ba160a7898ee4597d0f071cdea44.tar.gz
podman-d51727642603ba160a7898ee4597d0f071cdea44.tar.bz2
podman-d51727642603ba160a7898ee4597d0f071cdea44.zip
Add support for the global flags and config files
Note: This PR doesn't provide full rootless support that will be addressed in a future PR Signed-off-by: Jhon Honce <jhonce@redhat.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podmanV2/containers/mount.go3
-rw-r--r--cmd/podmanV2/containers/stop.go2
-rw-r--r--cmd/podmanV2/containers/wait.go2
-rw-r--r--cmd/podmanV2/main.go33
-rw-r--r--cmd/podmanV2/registry/config.go59
-rw-r--r--cmd/podmanV2/registry/registry.go38
-rw-r--r--cmd/podmanV2/registry/remote.go2
-rw-r--r--cmd/podmanV2/root.go168
8 files changed, 220 insertions, 87 deletions
diff --git a/cmd/podmanV2/containers/mount.go b/cmd/podmanV2/containers/mount.go
index c2f5ae987..4f7b95d98 100644
--- a/cmd/podmanV2/containers/mount.go
+++ b/cmd/podmanV2/containers/mount.go
@@ -31,6 +31,9 @@ var (
Args: func(cmd *cobra.Command, args []string) error {
return parse.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
+ Annotations: map[string]string{
+ registry.RootRequired: "true",
+ },
}
)
diff --git a/cmd/podmanV2/containers/stop.go b/cmd/podmanV2/containers/stop.go
index d6f31352f..53ec2934d 100644
--- a/cmd/podmanV2/containers/stop.go
+++ b/cmd/podmanV2/containers/stop.go
@@ -46,7 +46,7 @@ func init() {
flags.StringArrayVarP(&stopOptions.CIDFiles, "cidfile", "", nil, "Read the container ID from the file")
flags.BoolVarP(&stopOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.UintVarP(&stopTimeout, "time", "t", defaultContainerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
- if registry.EngineOptions.EngineMode == entities.ABIMode {
+ if registry.PodmanOptions.EngineMode == entities.ABIMode {
_ = flags.MarkHidden("latest")
_ = flags.MarkHidden("cidfile")
_ = flags.MarkHidden("ignore")
diff --git a/cmd/podmanV2/containers/wait.go b/cmd/podmanV2/containers/wait.go
index 2171f2073..3d11c581e 100644
--- a/cmd/podmanV2/containers/wait.go
+++ b/cmd/podmanV2/containers/wait.go
@@ -44,7 +44,7 @@ func init() {
flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
flags.BoolVarP(&waitOptions.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
- if registry.EngineOptions.EngineMode == entities.ABIMode {
+ if registry.PodmanOptions.EngineMode == entities.ABIMode {
// TODO: This is the same as V1. We could skip creating the flag altogether in V2...
_ = flags.MarkHidden("latest")
}
diff --git a/cmd/podmanV2/main.go b/cmd/podmanV2/main.go
index fe3cd9f16..cfe20d1c1 100644
--- a/cmd/podmanV2/main.go
+++ b/cmd/podmanV2/main.go
@@ -3,8 +3,6 @@ package main
import (
"os"
"reflect"
- "runtime"
- "strings"
_ "github.com/containers/libpod/cmd/podmanV2/containers"
_ "github.com/containers/libpod/cmd/podmanV2/healthcheck"
@@ -14,36 +12,13 @@ import (
"github.com/containers/libpod/cmd/podmanV2/registry"
_ "github.com/containers/libpod/cmd/podmanV2/system"
_ "github.com/containers/libpod/cmd/podmanV2/volumes"
- "github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/storage/pkg/reexec"
- "github.com/sirupsen/logrus"
)
func init() {
- if err := libpod.SetXdgDirs(); err != nil {
- logrus.Errorf(err.Error())
- os.Exit(1)
- }
-
- switch runtime.GOOS {
- case "darwin":
- fallthrough
- case "windows":
- registry.EngineOptions.EngineMode = entities.TunnelMode
- case "linux":
- registry.EngineOptions.EngineMode = entities.ABIMode
- default:
- logrus.Errorf("%s is not a supported OS", runtime.GOOS)
- os.Exit(1)
- }
-
- // TODO: Is there a Cobra way to "peek" at os.Args?
- for _, v := range os.Args {
- if strings.HasPrefix(v, "--remote") {
- registry.EngineOptions.EngineMode = entities.TunnelMode
- }
- }
+ // This is the bootstrap configuration, if user gives
+ // CLI flags parts of this configuration may be overwritten
+ registry.PodmanOptions = registry.NewPodmanConfig()
}
func main() {
@@ -53,7 +28,7 @@ func main() {
return
}
for _, c := range registry.Commands {
- if Contains(registry.EngineOptions.EngineMode, c.Mode) {
+ if Contains(registry.PodmanOptions.EngineMode, c.Mode) {
parent := rootCmd
if c.Parent != nil {
parent = c.Parent
diff --git a/cmd/podmanV2/registry/config.go b/cmd/podmanV2/registry/config.go
new file mode 100644
index 000000000..e68009a50
--- /dev/null
+++ b/cmd/podmanV2/registry/config.go
@@ -0,0 +1,59 @@
+package registry
+
+import (
+ "os"
+ "runtime"
+ "strings"
+
+ "github.com/containers/common/pkg/config"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/sirupsen/logrus"
+)
+
+const (
+ RootRequired = "RootRequired"
+)
+
+var (
+ PodmanOptions entities.PodmanConfig
+)
+
+// NewPodmanConfig creates a PodmanConfig from the environment
+func NewPodmanConfig() entities.PodmanConfig {
+ if err := libpod.SetXdgDirs(); err != nil {
+ logrus.Errorf(err.Error())
+ os.Exit(1)
+ }
+
+ var mode entities.EngineMode
+ switch runtime.GOOS {
+ case "darwin":
+ fallthrough
+ case "windows":
+ mode = entities.TunnelMode
+ case "linux":
+ mode = entities.ABIMode
+ default:
+ logrus.Errorf("%s is not a supported OS", runtime.GOOS)
+ os.Exit(1)
+ }
+
+ // cobra.Execute() may not be called yet, so we peek at os.Args.
+ for _, v := range os.Args {
+ // Prefix checking works because of how default EngineMode's
+ // have been defined.
+ if strings.HasPrefix(v, "--remote=") {
+ mode = entities.TunnelMode
+ }
+ }
+
+ // FIXME: for rootless, where to get the path
+ // TODO:
+ cfg, err := config.NewConfig("")
+ if err != nil {
+ logrus.Error("Failed to obtain podman configuration")
+ os.Exit(1)
+ }
+ return entities.PodmanConfig{Config: cfg, EngineMode: mode}
+}
diff --git a/cmd/podmanV2/registry/registry.go b/cmd/podmanV2/registry/registry.go
index 07c2b33ff..5ef6a10d8 100644
--- a/cmd/podmanV2/registry/registry.go
+++ b/cmd/podmanV2/registry/registry.go
@@ -29,8 +29,9 @@ var (
exitCode = ExecErrorCodeGeneric
imageEngine entities.ImageEngine
- Commands []CliCommand
- EngineOptions entities.EngineOptions
+ // Commands holds the cobra.Commands to present to the user, including
+ // parent if not a child of "root"
+ Commands []CliCommand
)
func SetExitCode(code int) {
@@ -83,8 +84,8 @@ func ImageEngine() entities.ImageEngine {
// NewImageEngine is a wrapper for building an ImageEngine to be used for PreRunE functions
func NewImageEngine(cmd *cobra.Command, args []string) (entities.ImageEngine, error) {
if imageEngine == nil {
- EngineOptions.FlagSet = cmd.Flags()
- engine, err := infra.NewImageEngine(EngineOptions)
+ PodmanOptions.FlagSet = cmd.Flags()
+ engine, err := infra.NewImageEngine(PodmanOptions)
if err != nil {
return nil, err
}
@@ -100,8 +101,8 @@ func ContainerEngine() entities.ContainerEngine {
// NewContainerEngine is a wrapper for building an ContainerEngine to be used for PreRunE functions
func NewContainerEngine(cmd *cobra.Command, args []string) (entities.ContainerEngine, error) {
if containerEngine == nil {
- EngineOptions.FlagSet = cmd.Flags()
- engine, err := infra.NewContainerEngine(EngineOptions)
+ PodmanOptions.FlagSet = cmd.Flags()
+ engine, err := infra.NewContainerEngine(PodmanOptions)
if err != nil {
return nil, err
}
@@ -125,24 +126,17 @@ func IdOrLatestArgs(cmd *cobra.Command, args []string) error {
return nil
}
-type podmanContextKey string
-
-var podmanFactsKey = podmanContextKey("engineOptions")
-
-func NewOptions(ctx context.Context, facts *entities.EngineOptions) context.Context {
- return context.WithValue(ctx, podmanFactsKey, facts)
-}
-
-func Options(cmd *cobra.Command) (*entities.EngineOptions, error) {
- if f, ok := cmd.Context().Value(podmanFactsKey).(*entities.EngineOptions); ok {
- return f, errors.New("Command Context ")
- }
- return nil, nil
-}
-
func GetContext() context.Context {
if cliCtx == nil {
- cliCtx = context.TODO()
+ cliCtx = context.Background()
}
return cliCtx
}
+
+type ContextOptionsKey string
+
+const PodmanOptionsKey ContextOptionsKey = "PodmanOptions"
+
+func GetContextWithOptions() context.Context {
+ return context.WithValue(GetContext(), PodmanOptionsKey, PodmanOptions)
+}
diff --git a/cmd/podmanV2/registry/remote.go b/cmd/podmanV2/registry/remote.go
index 32a231ac4..5378701e7 100644
--- a/cmd/podmanV2/registry/remote.go
+++ b/cmd/podmanV2/registry/remote.go
@@ -5,5 +5,5 @@ import (
)
func IsRemote() bool {
- return EngineOptions.EngineMode == entities.TunnelMode
+ return PodmanOptions.EngineMode == entities.TunnelMode
}
diff --git a/cmd/podmanV2/root.go b/cmd/podmanV2/root.go
index 6fc12f57e..6fc83a26b 100644
--- a/cmd/podmanV2/root.go
+++ b/cmd/podmanV2/root.go
@@ -1,29 +1,37 @@
package main
import (
+ "context"
"fmt"
"log/syslog"
"os"
"path"
+ "runtime/pprof"
"github.com/containers/libpod/cmd/podmanV2/registry"
"github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/tracing"
"github.com/containers/libpod/version"
+ "github.com/opentracing/opentracing-go"
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
logrusSyslog "github.com/sirupsen/logrus/hooks/syslog"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
)
var (
rootCmd = &cobra.Command{
- Use: path.Base(os.Args[0]),
- Long: "Manage pods, containers and images",
- SilenceUsage: true,
- SilenceErrors: true,
- TraverseChildren: true,
- PersistentPreRunE: preRunE,
- RunE: registry.SubCommandExists,
- Version: version.Version,
+ Use: path.Base(os.Args[0]),
+ Long: "Manage pods, containers and images",
+ SilenceUsage: true,
+ SilenceErrors: true,
+ TraverseChildren: true,
+ PersistentPreRunE: preRunE,
+ RunE: registry.SubCommandExists,
+ PersistentPostRunE: postRunE,
+ Version: version.Version,
}
logLevels = entities.NewStringSet("debug", "info", "warn", "error", "fatal", "panic")
@@ -32,30 +40,73 @@ var (
)
func init() {
- // Override default --help information of `--version` global flag}
- var dummyVersion bool
- // TODO had to disable shorthand -v for version due to -v rm with volume
- rootCmd.PersistentFlags().BoolVar(&dummyVersion, "version", false, "Version of Podman")
- rootCmd.PersistentFlags().StringVarP(&registry.EngineOptions.Uri, "remote", "r", "", "URL to access Podman service")
- rootCmd.PersistentFlags().StringSliceVar(&registry.EngineOptions.Identities, "identity", []string{}, "path to SSH identity file")
- rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "error", fmt.Sprintf("Log messages above specified level (%s)", logLevels.String()))
- rootCmd.PersistentFlags().BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)")
-
cobra.OnInitialize(
- logging,
+ rootlessHook,
+ loggingHook,
syslogHook,
)
+
+ rootFlags(registry.PodmanOptions, rootCmd.PersistentFlags())
+}
+
+func Execute() {
+ if err := rootCmd.ExecuteContext(registry.GetContextWithOptions()); err != nil {
+ logrus.Error(err)
+ } else if registry.GetExitCode() == registry.ExecErrorCodeGeneric {
+ // The exitCode modified from registry.ExecErrorCodeGeneric,
+ // indicates an application
+ // running inside of a container failed, as opposed to the
+ // podman command failed. Must exit with that exit code
+ // otherwise command exited correctly.
+ registry.SetExitCode(0)
+ }
+ os.Exit(registry.GetExitCode())
}
-func preRunE(cmd *cobra.Command, args []string) error {
+func preRunE(cmd *cobra.Command, _ []string) error {
+ // Update PodmanOptions now that we "know" more
+ // TODO: pass in path overriding configuration file
+ registry.PodmanOptions = registry.NewPodmanConfig()
+
cmd.SetHelpTemplate(registry.HelpTemplate())
cmd.SetUsageTemplate(registry.UsageTemplate())
+
+ if cmd.Flag("cpu_profile").Changed {
+ f, err := os.Create(registry.PodmanOptions.CpuProfile)
+ if err != nil {
+ return errors.Wrapf(err, "unable to create cpu profiling file %s",
+ registry.PodmanOptions.CpuProfile)
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ return err
+ }
+ }
+
+ if cmd.Flag("trace").Changed {
+ tracer, closer := tracing.Init("podman")
+ opentracing.SetGlobalTracer(tracer)
+ registry.PodmanOptions.SpanCloser = closer
+
+ registry.PodmanOptions.Span = tracer.StartSpan("before-context")
+ registry.PodmanOptions.SpanCtx = opentracing.ContextWithSpan(context.Background(), registry.PodmanOptions.Span)
+ }
return nil
}
-func logging() {
+func postRunE(cmd *cobra.Command, args []string) error {
+ if cmd.Flag("cpu-profile").Changed {
+ pprof.StopCPUProfile()
+ }
+ if cmd.Flag("trace").Changed {
+ registry.PodmanOptions.Span.Finish()
+ registry.PodmanOptions.SpanCloser.Close()
+ }
+ return nil
+}
+
+func loggingHook() {
if !logLevels.Contains(logLevel) {
- fmt.Fprintf(os.Stderr, "Log Level \"%s\" is not supported, choose from: %s\n", logLevel, logLevels.String())
+ logrus.Errorf("Log Level \"%s\" is not supported, choose from: %s", logLevel, logLevels.String())
os.Exit(1)
}
@@ -83,17 +134,68 @@ func syslogHook() {
}
}
-func Execute() {
- o := registry.NewOptions(rootCmd.Context(), &registry.EngineOptions)
- if err := rootCmd.ExecuteContext(o); err != nil {
- fmt.Fprintln(os.Stderr, "Error:", err.Error())
- } else if registry.GetExitCode() == registry.ExecErrorCodeGeneric {
- // The exitCode modified from registry.ExecErrorCodeGeneric,
- // indicates an application
- // running inside of a container failed, as opposed to the
- // podman command failed. Must exit with that exit code
- // otherwise command exited correctly.
- registry.SetExitCode(0)
+func rootlessHook() {
+ if rootless.IsRootless() {
+ logrus.Error("rootless mode is currently not supported. Support will return ASAP.")
}
- os.Exit(registry.GetExitCode())
+ // ce, err := registry.NewContainerEngine(rootCmd, []string{})
+ // if err != nil {
+ // logrus.WithError(err).Fatal("failed to obtain container engine")
+ // }
+ // ce.SetupRootLess(rootCmd)
+}
+
+func rootFlags(opts entities.PodmanConfig, flags *pflag.FlagSet) {
+ // V2 flags
+ flags.StringVarP(&opts.Uri, "remote", "r", "", "URL to access Podman service")
+ flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file")
+
+ // Override default --help information of `--version` global flag
+ // TODO: restore -v option for version without breaking -v for volumes
+ var dummyVersion bool
+ flags.BoolVar(&dummyVersion, "version", false, "Version of Podman")
+
+ cfg := opts.Config
+ flags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, opts.CGroupUsage)
+ flags.StringVar(&opts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
+ flags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
+ flags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
+ flags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
+ flags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
+ flags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
+ flags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
+ flags.IntVar(&opts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
+ flags.StringVar(&cfg.Engine.Namespace, "namespace", cfg.Engine.Namespace, "Set the libpod namespace, used to create separate views of the containers and pods on the system")
+ flags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
+ flags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
+ flags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
+ // -s is deprecated due to conflict with -s on subcommands
+ flags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
+ flags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
+
+ flags.StringVar(&opts.Engine.TmpDir, "tmpdir", "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
+ flags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
+
+ // Override default --help information of `--help` global flag
+ var dummyHelp bool
+ flags.BoolVar(&dummyHelp, "help", false, "Help for podman")
+ flags.StringVar(&logLevel, "log-level", logLevel, fmt.Sprintf("Log messages above specified level (%s)", logLevels.String()))
+
+ // Hide these flags for both ABI and Tunneling
+ for _, f := range []string{
+ "cpu-profile",
+ "default-mounts-file",
+ "max-workers",
+ "trace",
+ } {
+ if err := flags.MarkHidden(f); err != nil {
+ logrus.Warnf("unable to mark %s flag as hidden", f)
+ }
+ }
+
+ // Only create these flags for ABI connections
+ if !registry.IsRemote() {
+ flags.BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)")
+ }
+
}