Skip to content
Closed
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
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ require (
github.com/imdario/mergo v0.3.8 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/mikefarah/yq/v2 v2.4.1
github.com/onsi/ginkgo v1.12.0 // indirect
github.com/onsi/gomega v1.9.0 // indirect
github.com/onsi/ginkgo v1.12.0
github.com/onsi/gomega v1.9.0
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.1.0 // indirect
github.com/prometheus/procfs v0.0.5 // indirect
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.2.2
github.com/spf13/cobra v0.0.6
github.com/stretchr/testify v1.5.1
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 // indirect
Expand All @@ -26,4 +27,5 @@ require (
k8s.io/client-go v0.18.2
sigs.k8s.io/controller-runtime v0.6.0
sigs.k8s.io/controller-tools v0.3.0
sigs.k8s.io/yaml v1.2.0
)
3 changes: 2 additions & 1 deletion pkg/manifests/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

"github.com/operator-framework/api/pkg/metadata"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
)

Expand All @@ -18,7 +19,7 @@ type Bundle struct {
CSV *operatorsv1alpha1.ClusterServiceVersion
V1beta1CRDs []*apiextensionsv1beta1.CustomResourceDefinition
V1CRDs []*apiextensionsv1.CustomResourceDefinition
Dependencies []*Dependency
Dependencies []*metadata.Dependency
}

func (b *Bundle) ObjectsToValidate() []interface{} {
Expand Down
37 changes: 0 additions & 37 deletions pkg/manifests/bundlemeta.go

This file was deleted.

76 changes: 76 additions & 0 deletions pkg/metadata/directory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package metadata

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

log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice find!

)

// The bundle root-relative default annotations.yaml path.
var defaultRelPath = filepath.Join("metadata", "annotations.yaml")

// FindAnnotations walks bundleRoot searching for bundle metadata in an annotations.yaml file,
// and returns this metadata and its path if found. If one is not found, an error is returned.
func FindAnnotations(bundleRoot string) (AnnotationsFile, string, error) {
return findAnnotations(afero.NewOsFs(), bundleRoot)
}

func findAnnotations(fs afero.Fs, bundleRoot string) (AnnotationsFile, string, error) {
// Check the default path first, and return annotations if they were found or an error if that error
// is not because the path does not exist (it exists or there was an unmarshaling error).
annotationsPath := filepath.Join(bundleRoot, defaultRelPath)
af, err := readAnnotations(fs, annotationsPath)
if err != nil {
// Ignore this error, since the annotations might be in some other file.
log.Debug(err)
} else if !af.IsEmpty() {
return af, annotationsPath, nil
}

// Annotations are not at the default path, so search recursively.
foundAnnotations := false
annotationsPath = ""
err = afero.Walk(fs, bundleRoot, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Skip if annotations were already found, or path is a directory or hidden file.
if foundAnnotations || info.IsDir() || strings.HasPrefix(path, ".") {
return nil
}

annotationsPath = path
if af, err = readAnnotations(fs, path); err != nil {
// We don't want to stop early, so ignore this error and try other files.
log.Debug(err)
} else if !af.IsEmpty() {
foundAnnotations = true
}
return nil
})
if err != nil {
return af, "", err
}

if !foundAnnotations {
return af, "", fmt.Errorf("metadata not found in %s", bundleRoot)
}

return af, annotationsPath, nil
}

// readAnnotations attempts to read annotations from annotationsPath.
func readAnnotations(fs afero.Fs, annotationsPath string) (af AnnotationsFile, err error) {
b, err := afero.ReadFile(fs, annotationsPath)
if err != nil {
return af, err
}
if err = af.Unmarshal(b); err != nil {
return af, fmt.Errorf("error unmarshaling potential bundle metadata %s: %v", annotationsPath, err)
}
return af, nil
}
169 changes: 169 additions & 0 deletions pkg/metadata/directory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package metadata

import (
"path/filepath"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/spf13/afero"
)

var _ = Describe("Annotations", func() {
Describe("FindAnnotations", func() {
var (
fs afero.Fs
err error
defaultPath = "/bundle/metadata/annotations.yaml"
)

Context("with valid annotations contents", func() {
var (
annotationsFile AnnotationsFile
path, expPath string
)
BeforeEach(func() {
fs = afero.NewMemMapFs()
})

// Location
It("finds registry metadata in the default location", func() {
expPath = defaultPath
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})
It("finds registry metadata in the a custom file name", func() {
expPath = "/bundle/metadata/my-metadata.yaml"
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})
It("finds registry metadata in a custom single-depth location", func() {
expPath = "/bundle/my-dir/my-metadata.yaml"
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})
It("finds registry metadata in a custom multi-depth location", func() {
expPath = "/bundle/my-parent-dir/my-dir/annotations.yaml"
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})
It("returns registry metadata from default path when metadata is also in another location", func() {
expPath = defaultPath
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
writeMetadataHelper(fs, "/bundle/other-metadata/annotations.yaml", annotationsStringValidNoRegLabels)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})
It("returns registry metadata from the first path, when metadata is also in another location", func() {
expPath = "/bundle/custom1/annotations.yaml"
writeMetadataHelper(fs, expPath, annotationsStringValidV1)
writeMetadataHelper(fs, "/bundle/custom2/annotations.yaml", annotationsStringValidNoRegLabels)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidV1))
})

// Format
It("finds non-registry metadata", func() {
expPath = defaultPath
writeMetadataHelper(fs, defaultPath, annotationsStringValidNoRegLabels)
annotationsFile, path, err = findAnnotations(fs, "/bundle")
Expect(err).To(BeNil())
Expect(path).To(Equal(expPath))
Expect(annotationsFile).To(BeEquivalentTo(annotationsValidNoRegLabels))
})
})

Context("with invalid annotations contents", func() {
BeforeEach(func() {
fs = afero.NewMemMapFs()
})

It("returns an error for no metadata file (YAML error)", func() {
writeMetadataHelper(fs, defaultPath, annotationsStringInvalidBadIndent)
_, _, err = findAnnotations(fs, "/bundle")
Expect(err).To(MatchError("metadata not found in /bundle"))
})
It("returns an error for no metadata file (empty file)", func() {
writeMetadataHelper(fs, defaultPath, annotationsStringInvalidEmpty)
_, _, err = findAnnotations(fs, "/bundle")
Expect(err).To(MatchError("metadata not found in /bundle"))
})
It("returns an error for no metadata file (invalid top-level key)", func() {
writeMetadataHelper(fs, defaultPath, annotationsStringInvalidTopKey)
_, _, err = findAnnotations(fs, "/bundle")
Expect(err).To(MatchError("metadata not found in /bundle"))
})
It("returns an error for no labels in a metadata file", func() {
writeMetadataHelper(fs, defaultPath, annotationsStringInvalidNoLabels)
_, _, err = findAnnotations(fs, "/bundle")
Expect(err).To(MatchError("metadata not found in /bundle"))
})
})
})

})

func writeMetadataHelper(fs afero.Fs, path, contents string) {
ExpectWithOffset(1, fs.MkdirAll(filepath.Dir(path), 0755)).Should(Succeed())
ExpectWithOffset(1, afero.WriteFile(fs, path, []byte(contents), 0666)).Should(Succeed())
}

var annotationsValidV1 = AnnotationsFile{
Annotations: AnnotationsV1{
MediaType: "registry+v1",
MetadataDir: "metadata/",
AnnotationsRaw: map[string]string{
"foo": "bar",
},
},
}

const annotationsStringValidV1 = `annotations:
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
operators.operatorframework.io.bundle.metadata.v1: metadata/
foo: bar
`

var annotationsValidNoRegLabels = AnnotationsFile{
Annotations: AnnotationsV1{
AnnotationsRaw: map[string]string{
"foo": "bar",
"baz": "buf",
},
},
}

const annotationsStringValidNoRegLabels = `annotations:
foo: bar
baz: buf
`

const annotationsStringInvalidBadIndent = `annotations:
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
`

const annotationsStringInvalidEmpty = ``

const annotationsStringInvalidNoLabels = `annotations:
`

const annotationsStringInvalidTopKey = `not-annotations:
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
operators.operatorframework.io.bundle.metadata.v1: metadata/
foo: bar
`
13 changes: 13 additions & 0 deletions pkg/metadata/metadata_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package metadata

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestMetadata(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Metadata Suite")
}
Loading