Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
This commit modifies the scorecard config to be a componentconfig
versioned with other scorecard APIs in `pkg/apis/scorecard/v1alpha3`.
It also adds the `generate kustomize scorecard` subcommand,
which scaffolds componentconfig bases and patches in `config/scorecard`.
`generate kustomize manifests` will add the scorecard kustomize path
to the manifests kustomization.yaml, and `generate bundle` will write
the scorecard config to `bundle/tests/scorecard/config.yaml`

cmd/operator-sdk/generate: add `kustomize scorecard` subcommand and
modify `kustomize manifests` subcommand

pkg/apis/scorecard/v1alpha3: add ScorecardConfiguration types that map
to the original Config's types

internal/scorecard: replace Config type with v1alpha3.ScorecardConfiguration
and related types
  • Loading branch information
estroz committed Jul 23, 2020
commit e57e5ae92f0e2d19ae019bd2f42601c0c0185a55
32 changes: 29 additions & 3 deletions cmd/operator-sdk/generate/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/operator-framework/operator-sdk/internal/registry"
"github.com/operator-framework/operator-sdk/internal/scorecard"
"github.com/operator-framework/operator-sdk/internal/util/projutil"
"github.com/operator-framework/operator-sdk/pkg/apis/scorecard/v1alpha3"
)

const (
Expand Down Expand Up @@ -218,13 +219,37 @@ func (c bundleCmd) runManifests(cfg *config.Config) (err error) {
}
}

// Write the scorecard config if it was passed.
if err := writeScorecardConfig(c.outputDir, col.ScorecardConfig); err != nil {
return fmt.Errorf("error writing bundle scorecard config: %v", err)
}

if !c.quiet && !c.stdout {
fmt.Println("Bundle manifests generated successfully in", c.outputDir)
}

return nil
}

// writeScorecardConfig writes cfg to dir at the hard-coded config path 'config.yaml'.
func writeScorecardConfig(dir string, cfg v1alpha3.ScorecardConfiguration) error {
if cfg.Metadata.Name == "" {
return nil
}

b, err := yaml.Marshal(cfg)
if err != nil {
return err
}

cfgDir := filepath.Join(dir, filepath.FromSlash(scorecard.DefaultConfigDir))
if err := os.MkdirAll(cfgDir, 0755); err != nil {
return err
}
scorecardConfigPath := filepath.Join(cfgDir, scorecard.ConfigFileName)
return ioutil.WriteFile(scorecardConfigPath, b, 0666)
}

// validateMetadata validates c for bundle metadata generation.
func (c bundleCmd) validateMetadata(*config.Config) (err error) {
// Ensure a default channel is present.
Expand Down Expand Up @@ -282,6 +307,8 @@ func (c bundleCmd) generateMetadata(cfg *config.Config, manifestsDir, outputDir
return nil
}

// NB(estroz): these updates need to be atomic because the bundle's Dockerfile and annotations.yaml
// cannot be out-of-sync.
func updateMetadata(cfg *config.Config, bundleRoot string) error {
bundleLabels := metricsannotations.MakeBundleMetadataLabels(cfg)
for key, value := range scorecardannotations.MakeBundleMetadataLabels(scorecard.DefaultConfigDir) {
Expand All @@ -292,8 +319,6 @@ func updateMetadata(cfg *config.Config, bundleRoot string) error {
}

// Write labels to bundle Dockerfile.
// NB(estroz): these "rewrites" need to be atomic because the bundle's Dockerfile and annotations.yaml
// cannot be out-of-sync.
if err := rewriteDockerfileLabels(bundle.DockerFile, bundleLabels); err != nil {
return fmt.Errorf("error writing LABEL's in %s: %v", bundle.DockerFile, err)
}
Expand All @@ -303,7 +328,8 @@ func updateMetadata(cfg *config.Config, bundleRoot string) error {

// Add a COPY for the scorecard config to bundle Dockerfile.
// TODO: change input config path to be a flag-based value.
err := writeDockerfileCOPYScorecardConfig(bundle.DockerFile, filepath.FromSlash(scorecard.DefaultConfigDir))
localScorecardConfigPath := filepath.Join(bundleRoot, filepath.FromSlash(scorecard.DefaultConfigDir))
err := writeDockerfileCOPYScorecardConfig(bundle.DockerFile, localScorecardConfigPath)
if err != nil {
return fmt.Errorf("error writing scorecard config COPY in %s: %v", bundle.DockerFile, err)
}
Expand Down
3 changes: 3 additions & 0 deletions cmd/operator-sdk/generate/kustomize/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package kustomize

import (
"github.com/spf13/cobra"

"github.com/operator-framework/operator-sdk/cmd/operator-sdk/generate/kustomize/scorecard"
)

// NewCmd returns the 'kustomize' subcommand.
Expand All @@ -27,6 +29,7 @@ func NewCmd() *cobra.Command {

cmd.AddCommand(
newManifestsCmd(),
scorecard.NewCmd(),
)

return cmd
Expand Down
13 changes: 12 additions & 1 deletion cmd/operator-sdk/generate/kustomize/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package kustomize

import (
"fmt"
"os"
"path/filepath"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -174,8 +175,18 @@ func (c manifestsCmd) run(cfg *config.Config) error {
return fmt.Errorf("error generating kustomize bases: %v", err)
}

// NB(estroz): this is a rather hacky way of adding scorecard componentconfigs to the bundle,
// and won't work if the manifests kustomization.yaml already exists. This should be improved
// with scaffolding markers.
kustomization := manifestsKustomization

// Add a scorecard kustomization if one exists.
info, err := os.Stat(filepath.Join(filepath.Dir(c.outputDir), "scorecard"))
if err == nil && info.IsDir() {
kustomization += "- ../scorecard\n"
}
// Write a kustomization.yaml to outputDir if one does not exist.
if err := kustomize.WriteIfNotExist(c.outputDir, manifestsKustomization); err != nil {
if err := kustomize.WriteIfNotExist(c.outputDir, kustomization); err != nil {
return fmt.Errorf("error writing kustomization.yaml: %v", err)
}

Expand Down
133 changes: 133 additions & 0 deletions cmd/operator-sdk/generate/kustomize/scorecard/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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 scorecard

import (
"fmt"
"path/filepath"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"sigs.k8s.io/kubebuilder/pkg/model/config"

kbutil "github.com/operator-framework/operator-sdk/internal/util/kubebuilder"
)

const scorecardLongHelp = `
Running 'generate kustomize scorecard' will (re)generate scorecard configuration kustomize bases,
default test patches, and a kustomization.yaml in 'config/scorecard'.
`

const scorecardExamples = `
$ operator-sdk generate kustomize scorecard
Generating kustomize files in config/scorecard
Kustomize files generated successfully
$ tree ./config/scorecard
./config/scorecard/
├── bases
│   └── config.yaml
├── kustomization.yaml
└── patches
├── basic.config.yaml
└── olm.config.yaml
`

// defaultTestImageTag points to the latest-released image.
// TODO: change the tag to "latest" once config scaffolding is in a release,
// as the new config spec won't work with the current latest image.
const defaultTestImageTag = "quay.io/operator-framework/scorecard-test:master"

type scorecardCmd struct {
operatorName string
outputDir string
testImageTag string
quiet bool
}

// NewCmd returns the `scorecard` subcommand.
func NewCmd() *cobra.Command {
c := &scorecardCmd{}
cmd := &cobra.Command{
Use: "scorecard",
Short: "Generates scorecard configuration files",
Long: scorecardLongHelp,
Example: scorecardExamples,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return fmt.Errorf("command %s doesn't accept any arguments", cmd.CommandPath())
}

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(); err != nil {
log.Fatalf("Error generating kustomize files: %v", err)
}

return nil
},
}

c.addFlagsTo(cmd.Flags())

return cmd
}

func (c *scorecardCmd) addFlagsTo(fs *pflag.FlagSet) {
fs.StringVar(&c.operatorName, "operator-name", "", "Name of the operator")
fs.StringVar(&c.outputDir, "output-dir", "", "Directory to write kustomize files")
fs.StringVar(&c.testImageTag, "image", defaultTestImageTag,
"Image to use for default tests; this image must contain the `/scorecard-test` binary")
fs.BoolVarP(&c.quiet, "quiet", "q", false, "Run in quiet mode")
// NB(estroz): might be nice to have an --overwrite flag to explicitly turn on overwrite behavior (the current default).
}

// defaultDir is the default directory in which to generate kustomize bases and the kustomization.yaml.
var defaultDir = filepath.Join("config", "scorecard")

// setDefaults sets command defaults.
func (c *scorecardCmd) setDefaults(cfg *config.Config) {
if c.operatorName == "" {
c.operatorName = filepath.Base(cfg.Repo)
}

if c.outputDir == "" {
c.outputDir = defaultDir
}
}

// run scaffolds kustomize files for kustomizing a scorecard componentconfig.
func (c scorecardCmd) run() error {

if !c.quiet {
fmt.Println("Generating kustomize files in", c.outputDir)
}

err := generate(c.operatorName, c.testImageTag, c.outputDir)
if err != nil {
return err
}

if !c.quiet {
fmt.Println("Kustomize files generated successfully")
}

return nil
}
Loading