github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podmanV2/root.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log/syslog"
     7  	"os"
     8  	"path"
     9  	"runtime/pprof"
    10  
    11  	"github.com/containers/libpod/cmd/podmanV2/registry"
    12  	"github.com/containers/libpod/pkg/domain/entities"
    13  	"github.com/containers/libpod/pkg/rootless"
    14  	"github.com/containers/libpod/pkg/tracing"
    15  	"github.com/containers/libpod/version"
    16  	"github.com/opentracing/opentracing-go"
    17  	"github.com/pkg/errors"
    18  	"github.com/sirupsen/logrus"
    19  	logrusSyslog "github.com/sirupsen/logrus/hooks/syslog"
    20  	"github.com/spf13/cobra"
    21  	"github.com/spf13/pflag"
    22  )
    23  
    24  var (
    25  	rootCmd = &cobra.Command{
    26  		Use:                path.Base(os.Args[0]),
    27  		Long:               "Manage pods, containers and images",
    28  		SilenceUsage:       true,
    29  		SilenceErrors:      true,
    30  		TraverseChildren:   true,
    31  		PersistentPreRunE:  preRunE,
    32  		RunE:               registry.SubCommandExists,
    33  		PersistentPostRunE: postRunE,
    34  		Version:            version.Version,
    35  	}
    36  
    37  	logLevels = entities.NewStringSet("debug", "info", "warn", "error", "fatal", "panic")
    38  	logLevel  = "error"
    39  	useSyslog bool
    40  )
    41  
    42  func init() {
    43  	cobra.OnInitialize(
    44  		rootlessHook,
    45  		loggingHook,
    46  		syslogHook,
    47  	)
    48  
    49  	rootFlags(registry.PodmanOptions, rootCmd.PersistentFlags())
    50  }
    51  
    52  func Execute() {
    53  	if err := rootCmd.ExecuteContext(registry.GetContextWithOptions()); err != nil {
    54  		logrus.Error(err)
    55  	} else if registry.GetExitCode() == registry.ExecErrorCodeGeneric {
    56  		// The exitCode modified from registry.ExecErrorCodeGeneric,
    57  		// indicates an application
    58  		// running inside of a container failed, as opposed to the
    59  		// podman command failed.  Must exit with that exit code
    60  		// otherwise command exited correctly.
    61  		registry.SetExitCode(0)
    62  	}
    63  	os.Exit(registry.GetExitCode())
    64  }
    65  
    66  func preRunE(cmd *cobra.Command, _ []string) error {
    67  	// Update PodmanOptions now that we "know" more
    68  	// TODO: pass in path overriding configuration file
    69  	registry.PodmanOptions = registry.NewPodmanConfig()
    70  
    71  	cmd.SetHelpTemplate(registry.HelpTemplate())
    72  	cmd.SetUsageTemplate(registry.UsageTemplate())
    73  
    74  	if cmd.Flag("cpu-profile").Changed {
    75  		f, err := os.Create(registry.PodmanOptions.CpuProfile)
    76  		if err != nil {
    77  			return errors.Wrapf(err, "unable to create cpu profiling file %s",
    78  				registry.PodmanOptions.CpuProfile)
    79  		}
    80  		if err := pprof.StartCPUProfile(f); err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	if cmd.Flag("trace").Changed {
    86  		tracer, closer := tracing.Init("podman")
    87  		opentracing.SetGlobalTracer(tracer)
    88  		registry.PodmanOptions.SpanCloser = closer
    89  
    90  		registry.PodmanOptions.Span = tracer.StartSpan("before-context")
    91  		registry.PodmanOptions.SpanCtx = opentracing.ContextWithSpan(context.Background(), registry.PodmanOptions.Span)
    92  	}
    93  	return nil
    94  }
    95  
    96  func postRunE(cmd *cobra.Command, args []string) error {
    97  	if cmd.Flag("cpu-profile").Changed {
    98  		pprof.StopCPUProfile()
    99  	}
   100  	if cmd.Flag("trace").Changed {
   101  		registry.PodmanOptions.Span.Finish()
   102  		registry.PodmanOptions.SpanCloser.Close()
   103  	}
   104  	return nil
   105  }
   106  
   107  func loggingHook() {
   108  	if !logLevels.Contains(logLevel) {
   109  		logrus.Errorf("Log Level \"%s\" is not supported, choose from: %s", logLevel, logLevels.String())
   110  		os.Exit(1)
   111  	}
   112  
   113  	level, err := logrus.ParseLevel(logLevel)
   114  	if err != nil {
   115  		fmt.Fprintf(os.Stderr, err.Error())
   116  		os.Exit(1)
   117  	}
   118  	logrus.SetLevel(level)
   119  
   120  	if logrus.IsLevelEnabled(logrus.InfoLevel) {
   121  		logrus.Infof("%s filtering at log level %s", os.Args[0], logrus.GetLevel())
   122  	}
   123  }
   124  
   125  func syslogHook() {
   126  	if useSyslog {
   127  		hook, err := logrusSyslog.NewSyslogHook("", "", syslog.LOG_INFO, "")
   128  		if err != nil {
   129  			logrus.WithError(err).Error("Failed to initialize syslog hook")
   130  		}
   131  		if err == nil {
   132  			logrus.AddHook(hook)
   133  		}
   134  	}
   135  }
   136  
   137  func rootlessHook() {
   138  	if rootless.IsRootless() {
   139  		logrus.Error("rootless mode is currently not supported. Support will return ASAP.")
   140  	}
   141  	// ce, err := registry.NewContainerEngine(rootCmd, []string{})
   142  	// if err != nil {
   143  	// 	logrus.WithError(err).Fatal("failed to obtain container engine")
   144  	// }
   145  	// ce.SetupRootLess(rootCmd)
   146  }
   147  
   148  func rootFlags(opts entities.PodmanConfig, flags *pflag.FlagSet) {
   149  	// V2 flags
   150  	flags.StringVarP(&opts.Uri, "remote", "r", "", "URL to access Podman service")
   151  	flags.StringSliceVar(&opts.Identities, "identity", []string{}, "path to SSH identity file")
   152  
   153  	// Override default --help information of `--version` global flag
   154  	// TODO: restore -v option for version without breaking -v for volumes
   155  	var dummyVersion bool
   156  	flags.BoolVar(&dummyVersion, "version", false, "Version of Podman")
   157  
   158  	cfg := opts.Config
   159  	flags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, opts.CGroupUsage)
   160  	flags.StringVar(&opts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
   161  	flags.StringVar(&opts.ConmonPath, "conmon", "", "Path of the conmon binary")
   162  	flags.StringVar(&cfg.Engine.NetworkCmdPath, "network-cmd-path", cfg.Engine.NetworkCmdPath, "Path to the command for configuring the network")
   163  	flags.StringVar(&cfg.Network.NetworkConfigDir, "cni-config-dir", cfg.Network.NetworkConfigDir, "Path of the configuration directory for CNI networks")
   164  	flags.StringVar(&cfg.Containers.DefaultMountsFile, "default-mounts-file", cfg.Containers.DefaultMountsFile, "Path to default mounts file")
   165  	flags.StringVar(&cfg.Engine.EventsLogger, "events-backend", cfg.Engine.EventsLogger, `Events backend to use ("file"|"journald"|"none")`)
   166  	flags.StringSliceVar(&cfg.Engine.HooksDir, "hooks-dir", cfg.Engine.HooksDir, "Set the OCI hooks directory path (may be set multiple times)")
   167  	flags.IntVar(&opts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
   168  	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")
   169  	flags.StringVar(&cfg.Engine.StaticDir, "root", "", "Path to the root directory in which data, including images, is stored")
   170  	flags.StringVar(&opts.Runroot, "runroot", "", "Path to the 'run directory' where all state information is stored")
   171  	flags.StringVar(&opts.RuntimePath, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc")
   172  	// -s is deprecated due to conflict with -s on subcommands
   173  	flags.StringVar(&opts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)")
   174  	flags.StringArrayVar(&opts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver")
   175  
   176  	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")
   177  	flags.BoolVar(&opts.Trace, "trace", false, "Enable opentracing output (default false)")
   178  
   179  	// Override default --help information of `--help` global flag
   180  	var dummyHelp bool
   181  	flags.BoolVar(&dummyHelp, "help", false, "Help for podman")
   182  	flags.StringVar(&logLevel, "log-level", logLevel, fmt.Sprintf("Log messages above specified level (%s)", logLevels.String()))
   183  
   184  	// Hide these flags for both ABI and Tunneling
   185  	for _, f := range []string{
   186  		"cpu-profile",
   187  		"default-mounts-file",
   188  		"max-workers",
   189  		"trace",
   190  	} {
   191  		if err := flags.MarkHidden(f); err != nil {
   192  			logrus.Warnf("unable to mark %s flag as hidden", f)
   193  		}
   194  	}
   195  
   196  	// Only create these flags for ABI connections
   197  	if !registry.IsRemote() {
   198  		flags.BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)")
   199  	}
   200  
   201  }