@@ -2,11 +2,13 @@ package internal
2
2
3
3
import (
4
4
"fmt"
5
+ "strings"
5
6
6
7
"github.com/operator-framework/api/pkg/manifests"
7
8
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
8
9
"github.com/operator-framework/api/pkg/validation/errors"
9
10
interfaces "github.com/operator-framework/api/pkg/validation/interfaces"
11
+ "k8s.io/apimachinery/pkg/runtime/schema"
10
12
)
11
13
12
14
var BundleValidator interfaces.Validator = interfaces .ValidatorFunc (validateBundles )
@@ -28,39 +30,62 @@ func validateBundle(bundle *manifests.Bundle) (result errors.ManifestResult) {
28
30
}
29
31
30
32
func validateOwnedCRDs (bundle * manifests.Bundle , csv * operatorsv1alpha1.ClusterServiceVersion ) (result errors.ManifestResult ) {
31
- ownedCrdNames := getOwnedCustomResourceDefintionNames (csv )
32
- crdNames , err := getBundleCRDNames (bundle )
33
- if err != (errors.Error {}) {
34
- result .Add (err )
35
- return result
33
+ ownedKeys := getOwnedCustomResourceDefintionKeys (csv )
34
+
35
+ // Check for duplicate keys in the bundle, which may occur if a v1 and v1beta1 CRD of the same GVK appear.
36
+ keySet := make (map [schema.GroupVersionKind ]struct {})
37
+ for _ , key := range getBundleCRDKeys (bundle ) {
38
+ if _ , hasKey := keySet [key ]; hasKey {
39
+ result .Add (errors .ErrInvalidBundle (fmt .Sprintf ("duplicate CRD %q in bundle %q" , key , bundle .Name ), key ))
40
+ }
41
+ // Always add key to keySet so the below validations run correctly.
42
+ keySet [key ] = struct {}{}
36
43
}
37
44
38
- // validating names
39
- for _ , crdName := range ownedCrdNames {
40
- if _ , ok := crdNames [ crdName ]; ! ok {
41
- result .Add (errors .ErrInvalidBundle (fmt .Sprintf ("owned CRD %q not found in bundle %q" , crdName , bundle .Name ), crdName ))
45
+ // All owned keys must match a CRD in bundle.
46
+ for _ , ownedKey := range ownedKeys {
47
+ if _ , ok := keySet [ ownedKey ]; ! ok {
48
+ result .Add (errors .ErrInvalidBundle (fmt .Sprintf ("owned CRD %q not found in bundle %q" , ownedKey , bundle .Name ), ownedKey ))
42
49
} else {
43
- delete (crdNames , crdName )
50
+ delete (keySet , ownedKey )
44
51
}
45
52
}
46
- // CRDs not defined in the CSV present in the bundle
47
- for crdName := range crdNames {
48
- result .Add (errors .WarnInvalidBundle (fmt .Sprintf ("owned CRD %q is present in bundle %q but not defined in CSV" , crdName , bundle .Name ), crdName ))
53
+ // All CRDs present in a CSV must be present in the bundle.
54
+ for key := range keySet {
55
+ result .Add (errors .WarnInvalidBundle (fmt .Sprintf ("CRD %q is present in bundle %q but not defined in CSV" , key , bundle .Name ), key ))
49
56
}
57
+
50
58
return result
51
59
}
52
60
53
- func getOwnedCustomResourceDefintionNames (csv * operatorsv1alpha1.ClusterServiceVersion ) (names []string ) {
54
- for _ , ownedCrd := range csv .Spec .CustomResourceDefinitions .Owned {
55
- names = append (names , ownedCrd .Name )
61
+ // getBundleCRDKeys returns a list of definition keys for all owned CRDs in csv.
62
+ func getOwnedCustomResourceDefintionKeys (csv * operatorsv1alpha1.ClusterServiceVersion ) (keys []schema.GroupVersionKind ) {
63
+ for _ , owned := range csv .Spec .CustomResourceDefinitions .Owned {
64
+ group := owned .Name
65
+ if split := strings .SplitN (group , "." , 2 ); len (split ) == 2 {
66
+ group = split [1 ]
67
+ }
68
+ keys = append (keys , schema.GroupVersionKind {Group : group , Version : owned .Version , Kind : owned .Kind })
56
69
}
57
- return names
70
+ return keys
58
71
}
59
72
60
- func getBundleCRDNames (bundle * manifests.Bundle ) (map [string ]struct {}, errors.Error ) {
61
- crdNames := map [string ]struct {}{}
73
+ // getBundleCRDKeys returns a set of definition keys for all CRDs in bundle.
74
+ func getBundleCRDKeys (bundle * manifests.Bundle ) (keys []schema.GroupVersionKind ) {
75
+ // Collect all v1 and v1beta1 CRD keys, skipping group which CSVs do not support.
76
+ for _ , crd := range bundle .V1CRDs {
77
+ for _ , version := range crd .Spec .Versions {
78
+ keys = append (keys , schema.GroupVersionKind {Group : crd .Spec .Group , Version : version .Name , Kind : crd .Spec .Names .Kind })
79
+ }
80
+ }
62
81
for _ , crd := range bundle .V1beta1CRDs {
63
- crdNames [crd .GetName ()] = struct {}{}
82
+ if len (crd .Spec .Versions ) == 0 {
83
+ keys = append (keys , schema.GroupVersionKind {Group : crd .Spec .Group , Version : crd .Spec .Version , Kind : crd .Spec .Names .Kind })
84
+ } else {
85
+ for _ , version := range crd .Spec .Versions {
86
+ keys = append (keys , schema.GroupVersionKind {Group : crd .Spec .Group , Version : version .Name , Kind : crd .Spec .Names .Kind })
87
+ }
88
+ }
64
89
}
65
- return crdNames , errors. Error {}
90
+ return keys
66
91
}
0 commit comments