From d856fb43e11b3a4a93b423d330ce3435afddde4b Mon Sep 17 00:00:00 2001 From: Niall Crowe Date: Thu, 4 Aug 2022 09:02:54 +0100 Subject: Add "podman kube generate" command "podman kube generate" creates Kubernetes YAML from Podman containers, pods or volumes. Users will still be able to use "podman generate kube" as an alias of "kube generate". Signed-off-by: Niall Crowe --- cmd/podman/common/completion.go | 4 ++ cmd/podman/generate/generate.go | 6 +-- cmd/podman/generate/kube.go | 80 ----------------------------- cmd/podman/generate/spec.go | 4 +- cmd/podman/generate/systemd.go | 4 +- cmd/podman/kube/down.go | 2 +- cmd/podman/kube/generate.go | 109 ++++++++++++++++++++++++++++++++++++++++ cmd/podman/kube/kube.go | 4 +- cmd/podman/kube/play.go | 9 ++-- 9 files changed, 127 insertions(+), 95 deletions(-) delete mode 100644 cmd/podman/generate/kube.go create mode 100644 cmd/podman/kube/generate.go (limited to 'cmd') 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/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) { -- cgit v1.2.3-54-g00ecf