Skip to content

Commit dd85624

Browse files
committed
Move bundle validator back to registry under validation package
Move bundle validator from api back to registry and under validation package. The bundle validator is removed from api. Signed-off-by: Vu Dinh <[email protected]>
1 parent 42d3ba5 commit dd85624

File tree

137 files changed

+10441
-5366
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

137 files changed

+10441
-5366
lines changed

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ require (
3131
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
3232
github.com/opencontainers/runc v1.0.0-rc9 // indirect
3333
github.com/opencontainers/runtime-spec v0.1.2-0.20190618234442-a950415649c7 // indirect
34-
github.com/operator-framework/api v0.1.1
34+
github.com/operator-framework/api v0.3.4
3535
github.com/otiai10/copy v1.0.2
3636
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
3737
github.com/pkg/errors v0.9.1
@@ -45,10 +45,10 @@ require (
4545
google.golang.org/grpc v1.26.0
4646
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
4747
gopkg.in/yaml.v2 v2.2.8
48-
k8s.io/api v0.18.0
49-
k8s.io/apiextensions-apiserver v0.18.0
50-
k8s.io/apimachinery v0.18.0
51-
k8s.io/client-go v0.18.0
48+
k8s.io/api v0.18.2
49+
k8s.io/apiextensions-apiserver v0.18.2
50+
k8s.io/apimachinery v0.18.2
51+
k8s.io/client-go v0.18.2
5252
k8s.io/klog v1.0.0
5353
k8s.io/kubectl v0.18.0
5454
)

go.sum

Lines changed: 59 additions & 0 deletions
Large diffs are not rendered by default.

pkg/lib/bundle/validate.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
v1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
1111
v "github.com/operator-framework/api/pkg/validation"
1212
"github.com/operator-framework/operator-registry/pkg/containertools"
13+
validation "github.com/operator-framework/operator-registry/pkg/lib/validation"
1314
"github.com/operator-framework/operator-registry/pkg/registry"
1415

1516
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -355,7 +356,7 @@ func (i imageValidator) ValidateBundleContent(manifestDir string) error {
355356
// Validate the bundle object
356357
if len(unstObjs) > 0 {
357358
bundle := registry.NewBundle(csvName, "", nil, unstObjs...)
358-
bundleValidator := v.BundleValidator
359+
bundleValidator := validation.BundleValidator
359360
results := bundleValidator.Validate(bundle)
360361
if len(results) > 0 {
361362
for _, err := range results[0].Errors {

pkg/lib/bundle/validate_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,14 @@ func TestValidateBundleContent(t *testing.T) {
193193
mediaType: RegistryV1Type,
194194
directory: "./testdata/validate/invalid_manifests_bundle/invalid_bundle/",
195195
numErrors: 1,
196-
errString: `owned CRD "etcdclusters.etcd.database.coreos.com" not found in bundle`,
196+
errString: "owned CRD etcdclusters.etcd.database.coreos.com/v1beta2 not found in bundle",
197197
},
198198
{
199199
description: "invalid registryv1 bundle/extra crd",
200200
mediaType: RegistryV1Type,
201201
directory: "./testdata/validate/invalid_manifests_bundle/invalid_bundle_2/",
202202
numErrors: 1,
203-
errString: `owned CRD "etcdclusters.etcd.database.coreos.com" is present in bundle "etcdoperator.v0.9.4" but not defined in CSV`,
203+
errString: `CRD etcdclusters.etcd.database.coreos.com/v1beta2 is present in bundle "etcdoperator.v0.9.4" but not defined in CSV`,
204204
},
205205
}
206206

pkg/lib/validation/bundle.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package validation
2+
3+
import (
4+
"fmt"
5+
6+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
7+
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
8+
9+
"github.com/operator-framework/api/pkg/validation/errors"
10+
interfaces "github.com/operator-framework/api/pkg/validation/interfaces"
11+
"github.com/operator-framework/operator-registry/pkg/registry"
12+
)
13+
14+
var RegistryBundleValidator interfaces.Validator = interfaces.ValidatorFunc(validateBundles)
15+
16+
func validateBundles(objs ...interface{}) (results []errors.ManifestResult) {
17+
for _, obj := range objs {
18+
switch v := obj.(type) {
19+
case *registry.Bundle:
20+
results = append(results, validateBundle(v))
21+
}
22+
}
23+
return results
24+
}
25+
26+
func validateBundle(bundle *registry.Bundle) (result errors.ManifestResult) {
27+
csv, err := bundle.ClusterServiceVersion()
28+
if err != nil {
29+
result.Add(errors.ErrInvalidParse("error getting bundle CSV", err))
30+
return result
31+
}
32+
33+
result = validateOwnedCRDs(bundle, csv)
34+
35+
if result.Name, err = csv.GetVersion(); err != nil {
36+
result.Add(errors.ErrInvalidParse("error getting bundle CSV version", err))
37+
return result
38+
}
39+
return result
40+
}
41+
42+
func validateOwnedCRDs(bundle *registry.Bundle, csv *registry.ClusterServiceVersion) (result errors.ManifestResult) {
43+
ownedKeys, _, err := csv.GetCustomResourceDefintions()
44+
if err != nil {
45+
result.Add(errors.ErrInvalidParse("error getting CSV CRDs", err))
46+
return result
47+
}
48+
49+
keySet, rerr := getBundleCRDKeys(bundle)
50+
if rerr != (errors.Error{}) {
51+
result.Add(rerr)
52+
return result
53+
}
54+
55+
// Validate all owned keys, and remove them from the set if seen.
56+
for _, ownedKey := range ownedKeys {
57+
if _, ok := keySet[*ownedKey]; !ok {
58+
result.Add(errors.ErrInvalidBundle(fmt.Sprintf("owned CRD %s not found in bundle %q", keyToString(*ownedKey), bundle.Name), *ownedKey))
59+
} else {
60+
delete(keySet, *ownedKey)
61+
}
62+
}
63+
// CRDs not defined in the CSV present in the bundle
64+
for key := range keySet {
65+
result.Add(errors.WarnInvalidBundle(fmt.Sprintf("CRD %s is present in bundle %q but not defined in CSV", keyToString(key), bundle.Name), key))
66+
}
67+
return result
68+
}
69+
70+
func getBundleCRDKeys(bundle *registry.Bundle) (map[registry.DefinitionKey]struct{}, errors.Error) {
71+
crds, err := bundle.CustomResourceDefinitions()
72+
if err != nil {
73+
return nil, errors.ErrInvalidParse("error getting bundle CRDs", err)
74+
}
75+
keySet := map[registry.DefinitionKey]struct{}{}
76+
for _, c := range crds {
77+
switch crd := c.(type) {
78+
case *apiextensionsv1.CustomResourceDefinition:
79+
for _, version := range crd.Spec.Versions {
80+
// Skip group, which CSVs do not support.
81+
key := registry.DefinitionKey{
82+
Name: crd.GetName(),
83+
Version: version.Name,
84+
Kind: crd.Spec.Names.Kind,
85+
}
86+
keySet[key] = struct{}{}
87+
}
88+
case *apiextensionsv1beta1.CustomResourceDefinition:
89+
if crd.Spec.Version != "" {
90+
key := registry.DefinitionKey{
91+
Name: crd.GetName(),
92+
Version: crd.Spec.Version,
93+
Kind: crd.Spec.Names.Kind,
94+
}
95+
keySet[key] = struct{}{}
96+
} else {
97+
for _, version := range crd.Spec.Versions {
98+
// Skip group, which CSVs do not support.
99+
key := registry.DefinitionKey{
100+
Name: crd.GetName(),
101+
Version: version.Name,
102+
Kind: crd.Spec.Names.Kind,
103+
}
104+
keySet[key] = struct{}{}
105+
}
106+
}
107+
}
108+
}
109+
return keySet, errors.Error{}
110+
}
111+
112+
func keyToString(key registry.DefinitionKey) string {
113+
if key.Name == "" {
114+
return fmt.Sprintf("%s/%s %s", key.Group, key.Version, key.Kind)
115+
}
116+
return fmt.Sprintf("%s/%s", key.Name, key.Version)
117+
}

pkg/lib/validation/bundle_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package validation
2+
3+
import (
4+
"io/ioutil"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
9+
"github.com/operator-framework/operator-registry/pkg/registry"
10+
"github.com/stretchr/testify/require"
11+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12+
13+
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
14+
)
15+
16+
func TestValidateBundle(t *testing.T) {
17+
var table = []struct {
18+
description string
19+
directory string
20+
hasError bool
21+
errString string
22+
}{
23+
{
24+
description: "registryv1 bundle/valid bundle",
25+
directory: "./testdata/valid_bundle",
26+
hasError: false,
27+
},
28+
{
29+
description: "registryv1 bundle/invalid bundle",
30+
directory: "./testdata/invalid_bundle",
31+
hasError: true,
32+
errString: "owned CRD etcdclusters.etcd.database.coreos.com/v1beta2 not found in bundle",
33+
},
34+
{
35+
description: "registryv1 bundle/invalid bundle 2",
36+
directory: "./testdata/invalid_bundle_2",
37+
hasError: true,
38+
errString: `CRD etcdclusters.etcd.database.coreos.com/v1beta2 is present in bundle "test" but not defined in CSV`,
39+
},
40+
}
41+
42+
for _, tt := range table {
43+
unstObjs := []*unstructured.Unstructured{}
44+
45+
// Read all files in manifests directory
46+
items, err := ioutil.ReadDir(tt.directory)
47+
require.NoError(t, err, "Unable to read directory: %s", tt.description)
48+
49+
for _, item := range items {
50+
fileWithPath := filepath.Join(tt.directory, item.Name())
51+
data, err := ioutil.ReadFile(fileWithPath)
52+
require.NoError(t, err, "Unable to read file: %s", fileWithPath)
53+
54+
dec := k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30)
55+
k8sFile := &unstructured.Unstructured{}
56+
err = dec.Decode(k8sFile)
57+
require.NoError(t, err, "Unable to decode file: %s", fileWithPath)
58+
59+
unstObjs = append(unstObjs, k8sFile)
60+
}
61+
62+
// Validate the bundle object
63+
bundle := registry.NewBundle("test", "", nil, unstObjs...)
64+
results := BundleValidator.Validate(bundle)
65+
66+
if len(results) > 0 {
67+
require.Equal(t, tt.hasError, results[0].HasError(), "%s: %s", tt.description, results[0])
68+
if results[0].HasError() {
69+
require.Contains(t, results[0].Errors[0].Error(), tt.errString)
70+
}
71+
}
72+
}
73+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: etcdbackups.etcd.database.coreos.com
5+
spec:
6+
group: etcd.database.coreos.com
7+
names:
8+
kind: EtcdBackup
9+
listKind: EtcdBackupList
10+
plural: etcdbackups
11+
singular: etcdbackup
12+
scope: Namespaced
13+
version: v1beta2

0 commit comments

Comments
 (0)