diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/common/completion.go | 4 | ||||
-rw-r--r-- | cmd/podman/common/netflags.go | 13 | ||||
-rw-r--r-- | cmd/podman/generate/generate.go | 6 | ||||
-rw-r--r-- | cmd/podman/generate/kube.go | 80 | ||||
-rw-r--r-- | cmd/podman/generate/spec.go | 4 | ||||
-rw-r--r-- | cmd/podman/generate/systemd.go | 4 | ||||
-rw-r--r-- | cmd/podman/kube/down.go | 2 | ||||
-rw-r--r-- | cmd/podman/kube/generate.go | 109 | ||||
-rw-r--r-- | cmd/podman/kube/kube.go | 4 | ||||
-rw-r--r-- | cmd/podman/kube/play.go | 9 | ||||
-rw-r--r-- | cmd/podman/manifest/add.go | 12 | ||||
-rw-r--r-- | cmd/podman/manifest/create.go | 32 | ||||
-rw-r--r-- | cmd/podman/manifest/push.go | 15 | ||||
-rw-r--r-- | cmd/podman/root.go | 15 |
14 files changed, 207 insertions, 102 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 71c62a7af..b3a816aa4 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -544,6 +544,10 @@ func AutocompleteForKube(cmd *cobra.Command, args []string, toComplete string) ( return objs, cobra.ShellCompDirectiveNoFileComp } +func AutocompleteForGenerate(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return AutocompleteForKube(cmd, args, toComplete) +} + // AutocompleteContainersAndPods - Autocomplete container names and pod names. func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if !validCurrentCmdLine(cmd, args, toComplete) { diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go index e7aa265d1..90f05ab15 100644 --- a/cmd/podman/common/netflags.go +++ b/cmd/podman/common/netflags.go @@ -39,6 +39,11 @@ func DefineNetFlags(cmd *cobra.Command) { "Set custom DNS options", ) _ = cmd.RegisterFlagCompletionFunc(dnsOptFlagName, completion.AutocompleteNone) + netFlags.StringSlice( + "dns-option", containerConfig.DNSOptions(), + "Docker compatibility option== --dns-opt", + ) + _ = netFlags.MarkHidden("dns-option") dnsSearchFlagName := "dns-search" netFlags.StringSlice( @@ -146,6 +151,14 @@ func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*enti opts.DNSOptions = options } + if flags.Changed("dns-option") { + options, err := flags.GetStringSlice("dns-option") + if err != nil { + return nil, err + } + opts.DNSOptions = append(opts.DNSOptions, options...) + } + if flags.Changed("dns-search") { dnsSearches, err := flags.GetStringSlice("dns-search") if err != nil { diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go index 0a12961f4..f1dea6816 100644 --- a/cmd/podman/generate/generate.go +++ b/cmd/podman/generate/generate.go @@ -1,4 +1,4 @@ -package pods +package generate import ( "github.com/containers/podman/v4/cmd/podman/registry" @@ -9,7 +9,7 @@ import ( var ( // Command: podman _generate_ - generateCmd = &cobra.Command{ + GenerateCmd = &cobra.Command{ Use: "generate", Short: "Generate structured data based on containers, pods or volumes", Long: "Generate structured data (e.g., Kubernetes YAML or systemd units) based on containers, pods or volumes.", @@ -20,6 +20,6 @@ var ( func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ - Command: generateCmd, + Command: GenerateCmd, }) } diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go deleted file mode 100644 index 7bfc3dcf7..000000000 --- a/cmd/podman/generate/kube.go +++ /dev/null @@ -1,80 +0,0 @@ -package pods - -import ( - "fmt" - "io" - "io/ioutil" - "os" - - "github.com/containers/common/pkg/completion" - "github.com/containers/podman/v4/cmd/podman/common" - "github.com/containers/podman/v4/cmd/podman/registry" - "github.com/containers/podman/v4/cmd/podman/utils" - "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/spf13/cobra" -) - -var ( - kubeOptions = entities.GenerateKubeOptions{} - kubeFile = "" - kubeDescription = `Command generates Kubernetes Pod, Service or PersistenVolumeClaim YAML (v1 specification) from Podman containers, pods or volumes. - - Whether the input is for a container or pod, Podman will always generate the specification as a pod.` - - kubeCmd = &cobra.Command{ - Use: "kube [options] {CONTAINER...|POD...|VOLUME...}", - Short: "Generate Kubernetes YAML from containers, pods or volumes.", - Long: kubeDescription, - RunE: kube, - Args: cobra.MinimumNArgs(1), - ValidArgsFunction: common.AutocompleteForKube, - Example: `podman generate kube ctrID - podman generate kube podID - podman generate kube --service podID - podman generate kube volumeName - podman generate kube ctrID podID volumeName --service`, - } -) - -func init() { - registry.Commands = append(registry.Commands, registry.CliCommand{ - Command: kubeCmd, - Parent: generateCmd, - }) - flags := kubeCmd.Flags() - flags.BoolVarP(&kubeOptions.Service, "service", "s", false, "Generate YAML for a Kubernetes service object") - - filenameFlagName := "filename" - flags.StringVarP(&kubeFile, filenameFlagName, "f", "", "Write output to the specified path") - _ = kubeCmd.RegisterFlagCompletionFunc(filenameFlagName, completion.AutocompleteDefault) - - flags.SetNormalizeFunc(utils.AliasFlags) -} - -func kube(cmd *cobra.Command, args []string) error { - report, err := registry.ContainerEngine().GenerateKube(registry.GetContext(), args, kubeOptions) - if err != nil { - return err - } - - content, err := ioutil.ReadAll(report.Reader) - if err != nil { - return err - } - if r, ok := report.Reader.(io.ReadCloser); ok { - defer r.Close() - } - - if cmd.Flags().Changed("filename") { - if _, err := os.Stat(kubeFile); err == nil { - return fmt.Errorf("cannot write to %q; file exists", kubeFile) - } - if err := ioutil.WriteFile(kubeFile, content, 0644); err != nil { - return fmt.Errorf("cannot write to %q: %w", kubeFile, err) - } - return nil - } - - fmt.Println(string(content)) - return nil -} diff --git a/cmd/podman/generate/spec.go b/cmd/podman/generate/spec.go index 1cf967424..bf451ebc5 100644 --- a/cmd/podman/generate/spec.go +++ b/cmd/podman/generate/spec.go @@ -1,4 +1,4 @@ -package pods +package generate import ( "fmt" @@ -31,7 +31,7 @@ var ( func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Command: specCmd, - Parent: generateCmd, + Parent: GenerateCmd, }) opts = &entities.GenerateSpecOptions{} flags := specCmd.Flags() diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go index 1ece64a30..e40416534 100644 --- a/cmd/podman/generate/systemd.go +++ b/cmd/podman/generate/systemd.go @@ -1,4 +1,4 @@ -package pods +package generate import ( "encoding/json" @@ -57,7 +57,7 @@ var ( func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Command: systemdCmd, - Parent: generateCmd, + Parent: GenerateCmd, }) flags := systemdCmd.Flags() flags.BoolVarP(&systemdOptions.Name, "name", "n", false, "Use container/pod names instead of IDs") diff --git a/cmd/podman/kube/down.go b/cmd/podman/kube/down.go index b8c025928..a670d911c 100644 --- a/cmd/podman/kube/down.go +++ b/cmd/podman/kube/down.go @@ -1,4 +1,4 @@ -package pods +package kube import ( "github.com/containers/podman/v4/cmd/podman/common" diff --git a/cmd/podman/kube/generate.go b/cmd/podman/kube/generate.go new file mode 100644 index 000000000..6df4b55fc --- /dev/null +++ b/cmd/podman/kube/generate.go @@ -0,0 +1,109 @@ +package kube + +import ( + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/containers/common/pkg/completion" + "github.com/containers/podman/v4/cmd/podman/common" + "github.com/containers/podman/v4/cmd/podman/generate" + "github.com/containers/podman/v4/cmd/podman/registry" + "github.com/containers/podman/v4/cmd/podman/utils" + "github.com/containers/podman/v4/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + generateOptions = entities.GenerateKubeOptions{} + generateFile = "" + generateDescription = `Command generates Kubernetes Pod, Service or PersistenVolumeClaim YAML (v1 specification) from Podman containers, pods or volumes. + + Whether the input is for a container or pod, Podman will always generate the specification as a pod.` + + generateKubeCmd = &cobra.Command{ + Use: "generate [options] {CONTAINER...|POD...|VOLUME...}", + Short: "Generate Kubernetes YAML from containers, pods or volumes.", + Long: generateDescription, + RunE: generateKube, + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: common.AutocompleteForGenerate, + Example: `podman kube generate ctrID + podman kube generate podID + podman kube generate --service podID + podman kube generate volumeName + podman kube generate ctrID podID volumeName --service`, + } + kubeGenerateDescription = generateDescription + + kubeGenerateCmd = &cobra.Command{ + Use: "kube [options] {CONTAINER...|POD...|VOLUME...}", + Short: "Generate Kubernetes YAML from containers, pods or volumes.", + Long: kubeGenerateDescription, + RunE: kubeGenerate, + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: common.AutocompleteForGenerate, + Example: `podman kube generate ctrID + podman kube generate podID + podman kube generate --service podID + podman kube generate volumeName + podman kube generate ctrID podID volumeName --service`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: generateKubeCmd, + Parent: kubeCmd, + }) + generateFlags(generateKubeCmd) + + registry.Commands = append(registry.Commands, registry.CliCommand{ + Command: kubeGenerateCmd, + Parent: generate.GenerateCmd, + }) + generateFlags(kubeGenerateCmd) +} + +func generateFlags(cmd *cobra.Command) { + flags := cmd.Flags() + flags.BoolVarP(&generateOptions.Service, "service", "s", false, "Generate YAML for a Kubernetes service object") + + filenameFlagName := "filename" + flags.StringVarP(&generateFile, filenameFlagName, "f", "", "Write output to the specified path") + _ = cmd.RegisterFlagCompletionFunc(filenameFlagName, completion.AutocompleteDefault) + + flags.SetNormalizeFunc(utils.AliasFlags) +} + +func generateKube(cmd *cobra.Command, args []string) error { + report, err := registry.ContainerEngine().GenerateKube(registry.GetContext(), args, generateOptions) + if err != nil { + return err + } + content, err := ioutil.ReadAll(report.Reader) + if err != nil { + return err + } + if r, ok := report.Reader.(io.ReadCloser); ok { + defer r.Close() + } + + if cmd.Flags().Changed("filename") { + if _, err := os.Stat(generateFile); err == nil { + return fmt.Errorf("cannot write to %q; file exists", generateFile) + } + if err := ioutil.WriteFile(generateFile, content, 0644); err != nil { + return fmt.Errorf("cannot write to %q: %w", generateFile, err) + } + return nil + } + + fmt.Println(string(content)) + return nil +} + +func kubeGenerate(cmd *cobra.Command, args []string) error { + return generateKube(cmd, args) +} diff --git a/cmd/podman/kube/kube.go b/cmd/podman/kube/kube.go index 68f55a157..2dab68c19 100644 --- a/cmd/podman/kube/kube.go +++ b/cmd/podman/kube/kube.go @@ -1,4 +1,4 @@ -package pods +package kube import ( "github.com/containers/podman/v4/cmd/podman/registry" @@ -14,7 +14,7 @@ var ( Long: "Play structured data (e.g., Kubernetes YAML) based on containers, pods or volumes.", RunE: validate.SubCommandExists, } - + // Command: podman _play_ playKubeParentCmd = &cobra.Command{ Use: "play", Short: "Play containers, pods or volumes from a structured file", diff --git a/cmd/podman/kube/play.go b/cmd/podman/kube/play.go index 07c4b59b9..d7719e28e 100644 --- a/cmd/podman/kube/play.go +++ b/cmd/podman/kube/play.go @@ -1,4 +1,4 @@ -package pods +package kube import ( "bytes" @@ -47,7 +47,7 @@ var ( Use: "play [options] KUBEFILE|-", Short: "Play a pod or volume based on Kubernetes YAML.", Long: playDescription, - RunE: Play, + RunE: play, Args: cobra.ExactArgs(1), ValidArgsFunction: common.AutocompleteDefaultOneArg, Example: `podman kube play nginx.yml @@ -181,11 +181,10 @@ func playFlags(cmd *cobra.Command) { } } -func Play(cmd *cobra.Command, args []string) error { +func play(cmd *cobra.Command, args []string) error { if playOptions.ServiceContainer && !playOptions.StartCLI { // Sanity check to be future proof return fmt.Errorf("--service-container does not work with --start=stop") } - // TLS verification in c/image is controlled via a `types.OptionalBool` // which allows for distinguishing among set-true, set-false, unspecified // which is important to implement a sane way of dealing with defaults of @@ -260,7 +259,7 @@ func Play(cmd *cobra.Command, args []string) error { } func playKube(cmd *cobra.Command, args []string) error { - return Play(cmd, args) + return play(cmd, args) } func readerFromArg(fileName string) (*bytes.Reader, error) { diff --git a/cmd/podman/manifest/add.go b/cmd/podman/manifest/add.go index 35583ffcb..09a1a9a36 100644 --- a/cmd/podman/manifest/add.go +++ b/cmd/podman/manifest/add.go @@ -2,6 +2,7 @@ package manifest import ( "context" + "errors" "fmt" "github.com/containers/common/pkg/auth" @@ -20,6 +21,7 @@ type manifestAddOptsWrapper struct { entities.ManifestAddOptions TLSVerifyCLI bool // CLI only + Insecure bool // CLI only CredentialsCLI string } @@ -77,6 +79,8 @@ func init() { flags.StringVar(&manifestAddOpts.OSVersion, osVersionFlagName, "", "override the OS `version` of the specified image") _ = addCmd.RegisterFlagCompletionFunc(osVersionFlagName, completion.AutocompleteNone) + flags.BoolVar(&manifestAddOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") flags.BoolVar(&manifestAddOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") variantFlagName := "variant" @@ -89,7 +93,7 @@ func init() { } func add(cmd *cobra.Command, args []string) error { - if err := auth.CheckAuthFile(manifestPushOpts.Authfile); err != nil { + if err := auth.CheckAuthFile(manifestAddOpts.Authfile); err != nil { return err } @@ -109,6 +113,12 @@ func add(cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("tls-verify") { manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(!manifestAddOpts.TLSVerifyCLI) } + if cmd.Flags().Changed("insecure") { + if manifestAddOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestAddOpts.SkipTLSVerify = types.NewOptionalBool(manifestAddOpts.Insecure) + } listID, err := registry.ImageEngine().ManifestAdd(context.Background(), args[0], args[1:], manifestAddOpts.ManifestAddOptions) if err != nil { diff --git a/cmd/podman/manifest/create.go b/cmd/podman/manifest/create.go index 435b4a57c..0a0ea1d88 100644 --- a/cmd/podman/manifest/create.go +++ b/cmd/podman/manifest/create.go @@ -1,16 +1,26 @@ package manifest import ( + "errors" "fmt" + "github.com/containers/image/v5/types" "github.com/containers/podman/v4/cmd/podman/common" "github.com/containers/podman/v4/cmd/podman/registry" "github.com/containers/podman/v4/pkg/domain/entities" "github.com/spf13/cobra" ) +// manifestCreateOptsWrapper wraps entities.ManifestCreateOptions and prevents leaking +// CLI-only fields into the API types. +type manifestCreateOptsWrapper struct { + entities.ManifestCreateOptions + + TLSVerifyCLI, Insecure bool // CLI only +} + var ( - manifestCreateOpts = entities.ManifestCreateOptions{} + manifestCreateOpts = manifestCreateOptsWrapper{} createCmd = &cobra.Command{ Use: "create [options] LIST [IMAGE...]", Short: "Create manifest list or image index", @@ -32,10 +42,28 @@ func init() { }) flags := createCmd.Flags() flags.BoolVar(&manifestCreateOpts.All, "all", false, "add all of the lists' images if the images to add are lists") + flags.BoolVar(&manifestCreateOpts.Amend, "amend", false, "modify an existing list if one with the desired name already exists") + flags.BoolVar(&manifestCreateOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") + flags.BoolVar(&manifestCreateOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") } func create(cmd *cobra.Command, args []string) error { - imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts) + // TLS verification in c/image is controlled via a `types.OptionalBool` + // which allows for distinguishing among set-true, set-false, unspecified + // which is important to implement a sane way of dealing with defaults of + // boolean CLI flags. + if cmd.Flags().Changed("tls-verify") { + manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(!manifestCreateOpts.TLSVerifyCLI) + } + if cmd.Flags().Changed("insecure") { + if manifestCreateOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestCreateOpts.SkipTLSVerify = types.NewOptionalBool(manifestCreateOpts.Insecure) + } + + imageID, err := registry.ImageEngine().ManifestCreate(registry.Context(), args[0], args[1:], manifestCreateOpts.ManifestCreateOptions) if err != nil { return err } diff --git a/cmd/podman/manifest/push.go b/cmd/podman/manifest/push.go index 756ed2a74..fd67769b8 100644 --- a/cmd/podman/manifest/push.go +++ b/cmd/podman/manifest/push.go @@ -1,6 +1,7 @@ package manifest import ( + "errors" "fmt" "io/ioutil" @@ -20,9 +21,9 @@ import ( type manifestPushOptsWrapper struct { entities.ImagePushOptions - TLSVerifyCLI bool // CLI only - CredentialsCLI string - SignPassphraseFileCLI string + TLSVerifyCLI, Insecure bool // CLI only + CredentialsCLI string + SignPassphraseFileCLI string } var ( @@ -82,6 +83,8 @@ func init() { _ = pushCmd.RegisterFlagCompletionFunc(signPassphraseFileFlagName, completion.AutocompleteDefault) flags.BoolVar(&manifestPushOpts.TLSVerifyCLI, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry") + flags.BoolVar(&manifestPushOpts.Insecure, "insecure", false, "neither require HTTPS nor verify certificates when accessing the registry") + _ = flags.MarkHidden("insecure") flags.BoolVarP(&manifestPushOpts.Quiet, "quiet", "q", false, "don't output progress information when pushing lists") flags.SetNormalizeFunc(utils.AliasFlags) @@ -130,6 +133,12 @@ func push(cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("tls-verify") { manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(!manifestPushOpts.TLSVerifyCLI) } + if cmd.Flags().Changed("insecure") { + if manifestPushOpts.SkipTLSVerify != types.OptionalBoolUndefined { + return errors.New("--insecure may not be used with --tls-verify") + } + manifestPushOpts.SkipTLSVerify = types.NewOptionalBool(manifestPushOpts.Insecure) + } digest, err := registry.ImageEngine().ManifestPush(registry.Context(), args[0], args[1], manifestPushOpts.ImagePushOptions) if err != nil { return err diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 3637b2674..f45dc94b2 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -71,7 +71,10 @@ var ( DisableFlagsInUseLine: true, } - logLevel = "warn" + defaultLogLevel = "warn" + logLevel = defaultLogLevel + debug bool + useSyslog bool requireCleanup = true ) @@ -310,6 +313,13 @@ func persistentPostRunE(cmd *cobra.Command, args []string) error { func loggingHook() { var found bool + if debug { + if logLevel != defaultLogLevel { + fmt.Fprintf(os.Stderr, "Setting --log-level and --debug is not allowed\n") + os.Exit(1) + } + logLevel = "debug" + } for _, l := range common.LogLevels { if l == strings.ToLower(logLevel) { found = true @@ -465,6 +475,9 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags.StringVar(&logLevel, logLevelFlagName, logLevel, fmt.Sprintf("Log messages above specified level (%s)", strings.Join(common.LogLevels, ", "))) _ = rootCmd.RegisterFlagCompletionFunc(logLevelFlagName, common.AutocompleteLogLevel) + pFlags.BoolVar(&debug, "debug", false, "Docker compatibility, force setting of log-level") + _ = pFlags.MarkHidden("debug") + // Only create these flags for ABI connections if !registry.IsRemote() { runtimeflagFlagName := "runtime-flag" |