From af0926f5e119154822f9f965ca20f5f04dfb1a55 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Wed, 17 Jun 2020 19:30:24 -0700 Subject: [PATCH] Both `bundle` and `packagemanifests` generate the same set of kustomize files/bases, but in different directories. Instead of duplicating logic, `generate kustomize manifests` will now write operator-framework kustomize files to `config/manifests`. * cmd/operator-sdk/generate/kustomize: add `kustomize manifests` subcommand that generates kustomize bases and a `kustomization.yaml` in `config/manifests`. These files can be used by `generate ` --- changelog/fragments/generate-kustomize.yaml | 3 + cmd/operator-sdk/generate/cmd.go | 2 + cmd/operator-sdk/generate/kustomize/cmd.go | 33 +++ .../generate/kustomize/manifests.go | 189 ++++++++++++++++++ .../en/docs/new-cli/operator-sdk_generate.md | 1 + .../operator-sdk_generate_kustomize.md | 28 +++ ...erator-sdk_generate_kustomize_manifests.md | 68 +++++++ 7 files changed, 324 insertions(+) create mode 100644 changelog/fragments/generate-kustomize.yaml create mode 100644 cmd/operator-sdk/generate/kustomize/cmd.go create mode 100644 cmd/operator-sdk/generate/kustomize/manifests.go create mode 100644 website/content/en/docs/new-cli/operator-sdk_generate_kustomize.md create mode 100644 website/content/en/docs/new-cli/operator-sdk_generate_kustomize_manifests.md diff --git a/changelog/fragments/generate-kustomize.yaml b/changelog/fragments/generate-kustomize.yaml new file mode 100644 index 00000000000..6056070ebf9 --- /dev/null +++ b/changelog/fragments/generate-kustomize.yaml @@ -0,0 +1,3 @@ +entries: + - description: add `generate kustomize manifests` subcommand for new project layouts + kind: addition diff --git a/cmd/operator-sdk/generate/cmd.go b/cmd/operator-sdk/generate/cmd.go index 91b199aad41..12c1ff8d267 100644 --- a/cmd/operator-sdk/generate/cmd.go +++ b/cmd/operator-sdk/generate/cmd.go @@ -18,6 +18,7 @@ import ( "github.com/spf13/cobra" "github.com/operator-framework/operator-sdk/cmd/operator-sdk/generate/bundle" + "github.com/operator-framework/operator-sdk/cmd/operator-sdk/generate/kustomize" "github.com/operator-framework/operator-sdk/cmd/operator-sdk/generate/packagemanifests" ) @@ -34,6 +35,7 @@ code or manifests.`, func NewCmd() *cobra.Command { cmd := newCmd() cmd.AddCommand( + kustomize.NewCmd(), bundle.NewCmd(), packagemanifests.NewCmd(), ) diff --git a/cmd/operator-sdk/generate/kustomize/cmd.go b/cmd/operator-sdk/generate/kustomize/cmd.go new file mode 100644 index 00000000000..30ae4f00f57 --- /dev/null +++ b/cmd/operator-sdk/generate/kustomize/cmd.go @@ -0,0 +1,33 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kustomize + +import ( + "github.com/spf13/cobra" +) + +// NewCmd returns the 'kustomize' subcommand. +func NewCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "kustomize", + Short: "Contains subcommands that generate operator-framework kustomize data for the operator", + } + + cmd.AddCommand( + newManifestsCmd(), + ) + + return cmd +} diff --git a/cmd/operator-sdk/generate/kustomize/manifests.go b/cmd/operator-sdk/generate/kustomize/manifests.go new file mode 100644 index 00000000000..7af773cc339 --- /dev/null +++ b/cmd/operator-sdk/generate/kustomize/manifests.go @@ -0,0 +1,189 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kustomize + +import ( + "fmt" + "path/filepath" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "sigs.k8s.io/kubebuilder/pkg/model/config" + + genutil "github.com/operator-framework/operator-sdk/cmd/operator-sdk/generate/internal" + gencsv "github.com/operator-framework/operator-sdk/internal/generate/clusterserviceversion" + "github.com/operator-framework/operator-sdk/internal/scaffold/kustomize" + kbutil "github.com/operator-framework/operator-sdk/internal/util/kubebuilder" + "github.com/operator-framework/operator-sdk/internal/util/projutil" +) + +const longHelp = ` +Running 'generate kustomize manifests' will (re)generate kustomize bases and a kustomization.yaml in +'config/manifests', which are used to build operator-framework manifests by other operator-sdk commands. +This command will interactively ask for UI metadata, an important component of manifest bases, +by default unless a base already exists or you set '--interactive=false'. +` + +//nolint:lll +const examples = ` + $ operator-sdk generate kustomize manifests + + Display name for the operator (required): + > memcached-operator + ... + + $ tree config/manifests + config/manifests + ├── bases + │   └── memcached-operator.clusterserviceversion.yaml + └── kustomization.yaml + + # After generating kustomize bases and a kustomization.yaml, you can generate a bundle or package manifests. + + # To generate a bundle: + $ kustomize build config/manifests | operator-sdk generate bundle --version 0.0.1 + + # To generate package manifests: + $ kustomize build config/manifests | operator-sdk generate packagemanifests --version 0.0.1 +` + +//nolint:maligned +type manifestsCmd struct { + operatorName string + inputDir string + outputDir string + apisDir string + quiet bool + + // Interactive options. + interactiveLevel projutil.InteractiveLevel + interactive bool +} + +// newManifestsCmd returns the 'manifests' command configured for the new project layout. +func newManifestsCmd() *cobra.Command { + c := &manifestsCmd{} + cmd := &cobra.Command{ + Use: "manifests", + Short: "Generates kustomize bases and a kustomization.yaml for operator-framework manifests", + Long: longHelp, + Example: examples, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 0 { + return fmt.Errorf("command %s doesn't accept any arguments", cmd.CommandPath()) + } + + // Check if the user has any specific preference to enable/disable interactive prompts. + // Default behaviour is to disable the prompt unless a base does not exist. + if cmd.Flags().Changed("interactive") { + if c.interactive { + c.interactiveLevel = projutil.InteractiveOnAll + } else { + c.interactiveLevel = projutil.InteractiveHardOff + } + } + + cfg, err := kbutil.ReadConfig() + if err != nil { + return fmt.Errorf("error reading configuration: %v", err) + } + c.setDefaults(cfg) + + // Run command logic. + if err = c.run(cfg); err != nil { + log.Fatalf("Error generating kustomize files: %v", err) + } + + return nil + }, + } + + c.addFlagsTo(cmd.Flags()) + + return cmd +} + +func (c *manifestsCmd) addFlagsTo(fs *pflag.FlagSet) { + fs.StringVar(&c.operatorName, "operator-name", "", "Name of the operator") + fs.StringVar(&c.inputDir, "input-dir", "", "Directory containing existing kustomize files") + fs.StringVar(&c.outputDir, "output-dir", "", "Directory to write kustomize files") + fs.StringVar(&c.apisDir, "apis-dir", "", "Root directory for API type defintions") + fs.BoolVarP(&c.quiet, "quiet", "q", false, "Run in quiet mode") + fs.BoolVar(&c.interactive, "interactive", false, "When set or no kustomize base exists, an interactive "+ + "command prompt will be presented to accept non-inferrable metadata") +} + +// defaultDir is the default directory in which to generate kustomize bases and the kustomization.yaml. +var defaultDir = filepath.Join("config", "manifests") + +// setDefaults sets command defaults. +func (c *manifestsCmd) setDefaults(cfg *config.Config) { + if c.operatorName == "" { + c.operatorName = filepath.Base(cfg.Repo) + } + + if c.inputDir == "" { + c.inputDir = defaultDir + } + if c.outputDir == "" { + c.outputDir = defaultDir + } + if c.apisDir == "" { + if cfg.MultiGroup { + c.apisDir = "apis" + } else { + c.apisDir = "api" + } + } +} + +// kustomization.yaml file contents for manifests. this should always be written to +// config/manifests/kustomization.yaml since it only references files in config. +const manifestsKustomization = `resources: +- ../default +- ../samples +` + +// run generates kustomize bundle bases and a kustomization.yaml if one does not exist. +func (c manifestsCmd) run(cfg *config.Config) error { + + if !c.quiet { + fmt.Println("Generating kustomize files in", c.outputDir) + } + + csvGen := gencsv.Generator{ + OperatorName: c.operatorName, + OperatorType: genutil.PluginKeyToOperatorType(cfg.Layout), + } + opts := []gencsv.Option{ + gencsv.WithBase(c.inputDir, c.apisDir, c.interactiveLevel), + gencsv.WithBaseWriter(c.outputDir), + } + if err := csvGen.Generate(cfg, opts...); err != nil { + return fmt.Errorf("error generating kustomize bases: %v", err) + } + + // Write a kustomization.yaml to outputDir if one does not exist. + if err := kustomize.WriteIfNotExist(c.outputDir, manifestsKustomization); err != nil { + return fmt.Errorf("error writing kustomization.yaml: %v", err) + } + + if !c.quiet { + fmt.Println("Kustomize files generated successfully") + } + + return nil +} diff --git a/website/content/en/docs/new-cli/operator-sdk_generate.md b/website/content/en/docs/new-cli/operator-sdk_generate.md index b3d1edb816b..9e316c06954 100644 --- a/website/content/en/docs/new-cli/operator-sdk_generate.md +++ b/website/content/en/docs/new-cli/operator-sdk_generate.md @@ -26,5 +26,6 @@ code or manifests. * [operator-sdk](../operator-sdk) - Development kit for building Kubernetes extensions and tools. * [operator-sdk generate bundle](../operator-sdk_generate_bundle) - Generates bundle data for the operator +* [operator-sdk generate kustomize](../operator-sdk_generate_kustomize) - Contains subcommands that generate operator-framework kustomize data for the operator * [operator-sdk generate packagemanifests](../operator-sdk_generate_packagemanifests) - Generates a package manifests format diff --git a/website/content/en/docs/new-cli/operator-sdk_generate_kustomize.md b/website/content/en/docs/new-cli/operator-sdk_generate_kustomize.md new file mode 100644 index 00000000000..2e529b7d146 --- /dev/null +++ b/website/content/en/docs/new-cli/operator-sdk_generate_kustomize.md @@ -0,0 +1,28 @@ +--- +title: "operator-sdk generate kustomize" +--- +## operator-sdk generate kustomize + +Contains subcommands that generate operator-framework kustomize data for the operator + +### Synopsis + +Contains subcommands that generate operator-framework kustomize data for the operator + +### Options + +``` + -h, --help help for kustomize +``` + +### Options inherited from parent commands + +``` + --verbose Enable verbose logging +``` + +### SEE ALSO + +* [operator-sdk generate](../operator-sdk_generate) - Invokes a specific generator +* [operator-sdk generate kustomize manifests](../operator-sdk_generate_kustomize_manifests) - Generates kustomize bases and a kustomization.yaml for operator-framework manifests + diff --git a/website/content/en/docs/new-cli/operator-sdk_generate_kustomize_manifests.md b/website/content/en/docs/new-cli/operator-sdk_generate_kustomize_manifests.md new file mode 100644 index 00000000000..aab1204fd18 --- /dev/null +++ b/website/content/en/docs/new-cli/operator-sdk_generate_kustomize_manifests.md @@ -0,0 +1,68 @@ +--- +title: "operator-sdk generate kustomize manifests" +--- +## operator-sdk generate kustomize manifests + +Generates kustomize bases and a kustomization.yaml for operator-framework manifests + +### Synopsis + + +Running 'generate kustomize manifests' will (re)generate kustomize bases and a kustomization.yaml in +'config/manifests', which are used to build operator-framework manifests by other operator-sdk commands. +This command will interactively ask for UI metadata, an important component of manifest bases, +by default unless a base already exists or you set '--interactive=false'. + + +``` +operator-sdk generate kustomize manifests [flags] +``` + +### Examples + +``` + + $ operator-sdk generate kustomize manifests + + Display name for the operator (required): + > memcached-operator + ... + + $ tree config/manifests + config/manifests + ├── bases + │   └── memcached-operator.clusterserviceversion.yaml + └── kustomization.yaml + + # After generating kustomize bases and a kustomization.yaml, you can generate a bundle or package manifests. + + # To generate a bundle: + $ kustomize build config/manifests | operator-sdk generate bundle --version 0.0.1 + + # To generate package manifests: + $ kustomize build config/manifests | operator-sdk generate packagemanifests --version 0.0.1 + +``` + +### Options + +``` + --apis-dir string Root directory for API type defintions + -h, --help help for manifests + --input-dir string Directory containing existing kustomize files + --interactive When set or no kustomize base exists, an interactive command prompt will be presented to accept non-inferrable metadata + --operator-name string Name of the operator + --output-dir string Directory to write kustomize files + -q, --quiet Run in quiet mode +``` + +### Options inherited from parent commands + +``` + --verbose Enable verbose logging +``` + +### SEE ALSO + +* [operator-sdk generate kustomize](../operator-sdk_generate_kustomize) - Contains subcommands that generate operator-framework kustomize data for the operator +