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/kube/down.go | 2 +- cmd/podman/kube/generate.go | 109 ++++++++++++++++++++++++++++++++++++++++++++ cmd/podman/kube/kube.go | 4 +- cmd/podman/kube/play.go | 9 ++-- 4 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 cmd/podman/kube/generate.go (limited to 'cmd/podman/kube') 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