Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate (new CLI): add kustomize subcommand #3258

Merged
merged 1 commit into from
Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/fragments/generate-kustomize.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
entries:
- description: add `generate kustomize manifests` subcommand for new project layouts
kind: addition
2 changes: 2 additions & 0 deletions cmd/operator-sdk/generate/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -34,6 +35,7 @@ code or manifests.`,
func NewCmd() *cobra.Command {
cmd := newCmd()
cmd.AddCommand(
kustomize.NewCmd(),
bundle.NewCmd(),
packagemanifests.NewCmd(),
)
Expand Down
33 changes: 33 additions & 0 deletions cmd/operator-sdk/generate/kustomize/cmd.go
Original file line number Diff line number Diff line change
@@ -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
}
189 changes: 189 additions & 0 deletions cmd/operator-sdk/generate/kustomize/manifests.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions website/content/en/docs/new-cli/operator-sdk_generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

28 changes: 28 additions & 0 deletions website/content/en/docs/new-cli/operator-sdk_generate_kustomize.md
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -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