Skip to content

Commit c134fd6

Browse files
authored
internal/scaffold/crd.go: use structural schema for non-go operator CRDs (#2275)
* internal/scaffold/crd.go: use structural schema for non-go operator CRDs * CHANGELOG.md: update for #2275
1 parent b6581fd commit c134fd6

File tree

3 files changed

+67
-6
lines changed

3 files changed

+67
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- Updated `pkg/test/e2eutil.WaitForDeployment()` and `pkg/test/e2eutil.WaitForOperatorDeployment()` to successfully complete waiting when the available replica count is _at least_ (rather than exactly) the minimum replica count required. ([#2248](https://github.com/operator-framework/operator-sdk/pull/2248))
1313
- Replace in the Ansible based operators module tests `k8s_info` for `k8s_facts` which is deprecated. ([#2168](https://github.com/operator-framework/operator-sdk/issues/2168))
1414
- Upgrade the Ansible version from `2.8` to `2.9` on the Ansible based operators image. ([#2168](https://github.com/operator-framework/operator-sdk/issues/2168))
15+
- Updated CRD generation for non-Go operators to use valid structural schema. ([#2275](https://github.com/operator-framework/operator-sdk/issues/2275))
1516

1617
### Deprecated
1718

internal/scaffold/crd.go

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package scaffold
1616

1717
import (
18+
goerrors "errors"
1819
"fmt"
1920
"io"
2021
"os"
@@ -147,6 +148,10 @@ func (s *CRD) CustomRender() ([]byte, error) {
147148
return nil, err
148149
}
149150
}
151+
} else if goerrors.Is(err, afero.ErrFileNotFound) {
152+
crd = newCRDForResource(s.Resource)
153+
} else {
154+
return nil, err
150155
}
151156
}
152157

@@ -187,6 +192,7 @@ func runCRDGenerator(rule genall.OutputRule, root string) (err error) {
187192
}
188193

189194
func newCRDForResource(r *Resource) *apiextv1beta1.CustomResourceDefinition {
195+
trueVal := true
190196
crd := &apiextv1beta1.CustomResourceDefinition{
191197
TypeMeta: metav1.TypeMeta{
192198
APIVersion: apiextv1beta1.SchemeGroupVersion.String(),
@@ -204,6 +210,12 @@ func newCRDForResource(r *Resource) *apiextv1beta1.CustomResourceDefinition {
204210
Subresources: &apiextv1beta1.CustomResourceSubresources{
205211
Status: &apiextv1beta1.CustomResourceSubresourceStatus{},
206212
},
213+
Validation: &apiextv1beta1.CustomResourceValidation{
214+
OpenAPIV3Schema: &apiextv1beta1.JSONSchemaProps{
215+
Type: "object",
216+
XPreserveUnknownFields: &trueVal,
217+
},
218+
},
207219
},
208220
}
209221
setCRDNamesForResource(crd, r)

internal/scaffold/crd_test.go

+54-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"path/filepath"
2020
"testing"
2121

22+
"github.com/operator-framework/operator-sdk/internal/scaffold/input"
2223
testutil "github.com/operator-framework/operator-sdk/internal/scaffold/internal/testutil"
2324
"github.com/operator-framework/operator-sdk/internal/util/diffutil"
2425
"github.com/operator-framework/operator-sdk/internal/util/fileutil"
@@ -122,7 +123,54 @@ spec:
122123
storage: true
123124
`
124125

125-
func TestCRDNonGoProject(t *testing.T) {
126+
func TestCRDNonGoProjectDefault(t *testing.T) {
127+
s, buf := setupScaffoldAndWriter()
128+
s.Fs = afero.NewMemMapFs()
129+
130+
r, err := NewResource(appApiVersion, appKind)
131+
if err != nil {
132+
t.Fatal(err)
133+
}
134+
135+
crd := &CRD{Resource: r}
136+
cfg := &input.Config{}
137+
if err = s.Execute(cfg, crd); err != nil {
138+
t.Fatalf("Failed to execute the scaffold: (%v)", err)
139+
}
140+
141+
if crdNonGoDefaultExp != buf.String() {
142+
diffs := diffutil.Diff(crdNonGoDefaultExp, buf.String())
143+
t.Fatalf("Expected vs actual differs.\n%v", diffs)
144+
}
145+
}
146+
147+
// crdNonGoDefaultExp is the default non-go CRD. Non-go projects don't have the
148+
// luxury of kubebuilder annotations.
149+
const crdNonGoDefaultExp = `apiVersion: apiextensions.k8s.io/v1beta1
150+
kind: CustomResourceDefinition
151+
metadata:
152+
name: appservices.app.example.com
153+
spec:
154+
group: app.example.com
155+
names:
156+
kind: AppService
157+
listKind: AppServiceList
158+
plural: appservices
159+
singular: appservice
160+
scope: Namespaced
161+
subresources:
162+
status: {}
163+
validation:
164+
openAPIV3Schema:
165+
type: object
166+
x-kubernetes-preserve-unknown-fields: true
167+
versions:
168+
- name: v1alpha1
169+
served: true
170+
storage: true
171+
`
172+
173+
func TestCRDNonGoProjectCustom(t *testing.T) {
126174
s, buf := setupScaffoldAndWriter()
127175
s.Fs = afero.NewMemMapFs()
128176

@@ -142,7 +190,7 @@ func TestCRDNonGoProject(t *testing.T) {
142190
}
143191

144192
path := filepath.Join(cfg.AbsProjectPath, i.Path)
145-
err = afero.WriteFile(s.Fs, path, []byte(crdNonGoExp), fileutil.DefaultFileMode)
193+
err = afero.WriteFile(s.Fs, path, []byte(crdNonGoCustomExp), fileutil.DefaultFileMode)
146194
if err != nil {
147195
t.Fatal(err)
148196
}
@@ -151,16 +199,16 @@ func TestCRDNonGoProject(t *testing.T) {
151199
t.Fatalf("Failed to execute the scaffold: (%v)", err)
152200
}
153201

154-
if crdNonGoExp != buf.String() {
155-
diffs := diffutil.Diff(crdNonGoExp, buf.String())
202+
if crdNonGoCustomExp != buf.String() {
203+
diffs := diffutil.Diff(crdNonGoCustomExp, buf.String())
156204
t.Fatalf("Expected vs actual differs.\n%v", diffs)
157205
}
158206
}
159207

160-
// crdNonGoExp contains a simple validation block to make sure manually-added
208+
// crdNonGoCustomExp contains a simple validation block to make sure manually-added
161209
// validation is not overwritten. Non-go projects don't have the luxury of
162210
// kubebuilder annotations.
163-
const crdNonGoExp = `apiVersion: apiextensions.k8s.io/v1beta1
211+
const crdNonGoCustomExp = `apiVersion: apiextensions.k8s.io/v1beta1
164212
kind: CustomResourceDefinition
165213
metadata:
166214
name: appservices.app.example.com

0 commit comments

Comments
 (0)