Skip to content

Commit

Permalink
Switch the bundle validate to use the API
Browse files Browse the repository at this point in the history
This uses the validators directly, but still has the same usage
semantics, for the most part.

Signed-off-by: Brad P. Crochet <brad@redhat.com>
  • Loading branch information
bcrochet committed Aug 26, 2022
1 parent bd6549e commit ffec18f
Show file tree
Hide file tree
Showing 16 changed files with 641 additions and 222 deletions.
4 changes: 2 additions & 2 deletions certification/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ func initializeChecks(ctx context.Context, p policy.Policy, cfg certification.Co
return []certification.Check{
operatorpol.NewScorecardBasicSpecCheck(operatorsdk.New(cfg.ScorecardImage(), exec.Command), cfg.Namespace(), cfg.ServiceAccount(), cfg.Kubeconfig(), cfg.ScorecardWaitTime()),
operatorpol.NewScorecardOlmSuiteCheck(operatorsdk.New(cfg.ScorecardImage(), exec.Command), cfg.Namespace(), cfg.ServiceAccount(), cfg.Kubeconfig(), cfg.ScorecardWaitTime()),
operatorpol.NewDeployableByOlmCheck(operatorsdk.New(cfg.ScorecardImage(), exec.Command), cfg.IndexImage(), cfg.DockerConfig(), cfg.Channel()),
operatorpol.NewValidateOperatorBundleCheck(operatorsdk.New(cfg.ScorecardImage(), exec.Command)),
operatorpol.NewDeployableByOlmCheck(cfg.IndexImage(), cfg.DockerConfig(), cfg.Channel()),
operatorpol.NewValidateOperatorBundleCheck(),
operatorpol.NewCertifiedImagesCheck(pyxis.NewPyxisClient(
certification.DefaultPyxisHost,
"",
Expand Down
45 changes: 29 additions & 16 deletions certification/internal/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (

"github.com/blang/semver"
"github.com/operator-framework/api/pkg/manifests"
"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/operatorsdk"
"github.com/operator-framework/api/pkg/validation"
olmvalidation "github.com/redhat-openshift-ecosystem/ocp-olm-catalog-validator/pkg/validation"
log "github.com/sirupsen/logrus"
"sigs.k8s.io/yaml"
)
Expand All @@ -29,21 +30,22 @@ var ocpToKubeVersion = map[string]string{

const latestReleasedVersion = "4.11"

type operatorSdk interface {
BundleValidate(context.Context, string, operatorsdk.OperatorSdkBundleValidateOptions) (*operatorsdk.OperatorSdkBundleValidateReport, error)
}
func Validate(ctx context.Context, imagePath string) (*Report, error) {
log.Trace("reading annotations file from the bundle")
log.Debug("image extraction directory is ", imagePath)

func Validate(ctx context.Context, operatorSdk operatorSdk, imagePath string) (*operatorsdk.OperatorSdkBundleValidateReport, error) {
selector := []string{"community", "operatorhub", "alpha-deprecated-apis"}
opts := operatorsdk.OperatorSdkBundleValidateOptions{
Selector: selector,
Verbose: true,
ContainerEngine: "none",
OutputFormat: "json-alpha1",
bundle, err := manifests.GetBundleFromDir(imagePath)
if err != nil {
return nil, fmt.Errorf("could not load bundle from path: %s: %v", imagePath, err)
}
validators := validation.DefaultBundleValidators.WithValidators(
validation.AlphaDeprecatedAPIsValidator,
validation.OperatorHubValidator,
olmvalidation.OpenShiftValidator,
)

objs := bundle.ObjectsToValidate()

log.Trace("reading annotations file from the bundle")
log.Debug("image extraction directory is ", imagePath)
// retrieve the operator metadata from bundle image
annotationsFileName := filepath.Join(imagePath, "metadata", "annotations.yaml")
annotationsFile, err := os.Open(annotationsFileName)
Expand All @@ -55,6 +57,7 @@ func Validate(ctx context.Context, operatorSdk operatorSdk, imagePath string) (*
return nil, fmt.Errorf("unable to get annotations.yaml from the bundle: %v", err)
}

optionalValues := make(map[string]string)
if annotations.OpenshiftVersions != "" {
// Check that the label range contains >= 4.9
targetVersion, err := targetVersion(annotations.OpenshiftVersions)
Expand All @@ -64,12 +67,22 @@ func Validate(ctx context.Context, operatorSdk operatorSdk, imagePath string) (*
}
if k8sVer, found := ocpToKubeVersion[targetVersion]; found {
log.Debugf("OpenShift %s detected in annotations. Running with additional checks enabled.", targetVersion)
opts.OptionalValues = make(map[string]string)
opts.OptionalValues["k8s-version"] = k8sVer
optionalValues = make(map[string]string)
optionalValues["k8s-version"] = k8sVer
}
}
objs = append(objs, optionalValues)

results := validators.Validate(objs...)
passed := true
for _, v := range results {
if v.HasError() {
passed = false
break
}
}

return operatorSdk.BundleValidate(ctx, imagePath, opts)
return &Report{Results: results, Passed: passed}, nil
}

func targetVersion(ocpLabelIndex string) (string, error) {
Expand Down
12 changes: 0 additions & 12 deletions certification/internal/bundle/bundle_suite_test.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,18 @@
package bundle

import (
"context"
"errors"
"testing"

. "github.com/onsi/ginkgo/v2/dsl/core"
. "github.com/onsi/gomega"

"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/operatorsdk"
)

func TestBundle(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Bundle Utils Suite")
}

type FakeOperatorSdk struct {
OperatorSdkReport operatorsdk.OperatorSdkScorecardReport
OperatorSdkBVReport operatorsdk.OperatorSdkBundleValidateReport
}

func (f FakeOperatorSdk) BundleValidate(ctx context.Context, image string, opts operatorsdk.OperatorSdkBundleValidateOptions) (*operatorsdk.OperatorSdkBundleValidateReport, error) {
return &f.OperatorSdkBVReport, nil
}

// In order to test some negative paths, this io.Reader will just throw an error
type errReader int

Expand Down
25 changes: 14 additions & 11 deletions certification/internal/bundle/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"os"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo/v2/dsl/core"
. "github.com/onsi/ginkgo/v2/dsl/table"
. "github.com/onsi/gomega"
"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
)
Expand All @@ -22,7 +23,9 @@ var _ = Describe("BundleValidateCheck", func() {
operators.operatorframework.io.bundle.package.v1: testPackage
operators.operatorframework.io.bundle.channel.default.v1: testChannel
`
csvContents = `spec:
csvContents = `apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
spec:
install:
spec:
deployments:
Expand All @@ -40,10 +43,7 @@ var _ = Describe("BundleValidateCheck", func() {
)

Describe("Bundle validation", func() {
var (
imageRef certification.ImageReference
fakeEngine operatorSdk
)
var imageRef certification.ImageReference

BeforeEach(func() {
// mock bundle directory
Expand All @@ -56,11 +56,14 @@ var _ = Describe("BundleValidateCheck", func() {
err = os.Mkdir(filepath.Join(tmpDir, manifestsDir), 0o755)
Expect(err).ToNot(HaveOccurred())

err = os.WriteFile(filepath.Join(tmpDir, manifestsDir, clusterServiceVersionFilename), []byte(csvContents), 0o644)
Expect(err).ToNot(HaveOccurred())

err = os.WriteFile(filepath.Join(tmpDir, metadataDir, annotationFilename), []byte(annotations), 0o644)
Expect(err).ToNot(HaveOccurred())

imageRef.ImageFSPath = tmpDir
fakeEngine = FakeOperatorSdk{}
DeferCleanup(os.RemoveAll, tmpDir)
})

AfterEach(func() {
Expand All @@ -70,7 +73,7 @@ var _ = Describe("BundleValidateCheck", func() {

Context("the annotations file is valid", func() {
It("should pass", func() {
report, err := Validate(context.Background(), fakeEngine, imageRef.ImageFSPath)
report, err := Validate(context.Background(), imageRef.ImageFSPath)
Expect(err).ToNot(HaveOccurred())
Expect(report).ToNot(BeNil())
})
Expand All @@ -82,7 +85,7 @@ var _ = Describe("BundleValidateCheck", func() {
Expect(err).ToNot(HaveOccurred())
})
It("should error", func() {
report, err := Validate(context.Background(), fakeEngine, imageRef.ImageFSPath)
report, err := Validate(context.Background(), imageRef.ImageFSPath)
Expect(err).To(HaveOccurred())
Expect(report).To(BeNil())
})
Expand All @@ -94,7 +97,7 @@ var _ = Describe("BundleValidateCheck", func() {
Expect(err).ToNot(HaveOccurred())
})
It("should error", func() {
report, err := Validate(context.Background(), fakeEngine, imageRef.ImageFSPath)
report, err := Validate(context.Background(), imageRef.ImageFSPath)
Expect(err).To(HaveOccurred())
Expect(report).To(BeNil())
})
Expand All @@ -106,7 +109,7 @@ var _ = Describe("BundleValidateCheck", func() {
Expect(err).ToNot(HaveOccurred())
})
It("should fail gracefully", func() {
report, err := Validate(context.Background(), fakeEngine, imageRef.ImageFSPath)
report, err := Validate(context.Background(), imageRef.ImageFSPath)
Expect(err).ToNot(HaveOccurred())
Expect(report).ToNot(BeNil())
})
Expand Down
10 changes: 9 additions & 1 deletion certification/internal/bundle/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package bundle

import "github.com/operator-framework/api/pkg/manifests"
import (
"github.com/operator-framework/api/pkg/manifests"
validationerrors "github.com/operator-framework/api/pkg/validation/errors"
)

type AnnotationsFile struct {
Annotations Annotations `json:"annotations" yaml:"annotations"`
Expand All @@ -11,3 +14,8 @@ type Annotations struct {

OpenshiftVersions string `json:"com.redhat.openshift.versions,omitempty" yaml:"com.redhat.openshift.versions,omitempty"`
}

type Report struct {
Results []validationerrors.ManifestResult
Passed bool
}
7 changes: 2 additions & 5 deletions certification/internal/policy/operator/deployable_by_olm.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ type DeployableByOlmCheck struct {
// channel is optional. If empty, we will introspect.
channel string

OperatorSdk operatorSdk
openshiftClient openshift.Client
client crclient.Client
csvReady bool
Expand Down Expand Up @@ -94,13 +93,11 @@ func (p *DeployableByOlmCheck) initOpenShifeEngine() error {
// in scope are public. An empty channel value implies that the check should
// introspect the channel from the bundle. indexImage is required.
func NewDeployableByOlmCheck(
operatorSdk operatorSdk,
indexImage,
dockerConfig,
channel string,
) *DeployableByOlmCheck {
return &DeployableByOlmCheck{
OperatorSdk: operatorSdk,
dockerConfig: dockerConfig,
indexImage: indexImage,
channel: channel,
Expand All @@ -110,7 +107,7 @@ func NewDeployableByOlmCheck(
func (p *DeployableByOlmCheck) Validate(ctx context.Context, bundleRef certification.ImageReference) (bool, error) {
p.initClient()
p.initOpenShifeEngine()
if report, err := bundle.Validate(ctx, p.OperatorSdk, bundleRef.ImageFSPath); err != nil || !report.Passed {
if report, err := bundle.Validate(ctx, bundleRef.ImageFSPath); err != nil || !report.Passed {
return false, fmt.Errorf("%v", err)
}

Expand Down Expand Up @@ -640,6 +637,6 @@ func (p *DeployableByOlmCheck) Metadata() certification.Metadata {
func (p *DeployableByOlmCheck) Help() certification.HelpText {
return certification.HelpText{
Message: "It is required that your operator could be deployed by OLM",
Suggestion: "Follow the guidelines on the operatorsdk website to learn how to package your operator https://sdk.operatorframework.io/docs/olm-integration/cli-overview/",
Suggestion: "Follow the guidelines on the operator-sdk website to learn how to package your operator https://sdk.operatorframework.io/docs/olm-integration/cli-overview/",
}
}
Loading

0 comments on commit ffec18f

Please sign in to comment.