Skip to content

Commit c7e942a

Browse files
author
Per Goncalves da Silva
committed
Add olmv1 webhook support origin tests
Signed-off-by: Per Goncalves da Silva <[email protected]>
1 parent 95fc9bc commit c7e942a

File tree

9 files changed

+575
-0
lines changed

9 files changed

+575
-0
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
package operators
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
8+
"path/filepath"
9+
"time"
10+
11+
g "github.com/onsi/ginkgo/v2"
12+
o "github.com/onsi/gomega"
13+
"k8s.io/apimachinery/pkg/api/meta"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/util/wait"
16+
17+
exutil "github.com/openshift/origin/test/extended/util"
18+
)
19+
20+
const (
21+
conditionTypeServing = "Serving"
22+
conditionTypeInstalled = "Installed"
23+
)
24+
25+
var (
26+
webhookTestBaseDir = exutil.FixturePath("testdata", "olmv1", "webhook-support")
27+
)
28+
29+
var _ = g.Describe("[sig-olmv1][OCPFeatureGate:NewOLMWebhookProviderOpenshiftServiceCA][Skipped:Disconnected] OLMv1 support for bundles with webhooks", g.Ordered, func() {
30+
var (
31+
cleanUpCatalog, cleanUpExtension = func() {}, func() {}
32+
)
33+
defer g.GinkgoRecover()
34+
35+
oc := exutil.NewCLI("openshift-operator-controller")
36+
37+
g.BeforeAll(func(ctx g.SpecContext) {
38+
checkFeatureCapability(oc)
39+
cleanUpCatalog = installWebhookOperatorClusterCatalog(ctx, oc)
40+
cleanUpExtension = installWebhookOperator(ctx, oc)
41+
})
42+
43+
g.BeforeEach(func() {
44+
exutil.PreTestDump()
45+
})
46+
47+
g.AfterEach(func() {
48+
if g.CurrentSpecReport().Failed() {
49+
exutil.DumpPodLogsStartingWith("", oc)
50+
}
51+
})
52+
53+
g.AfterAll(func(ctx g.SpecContext) {
54+
cleanUpExtension()
55+
cleanUpCatalog()
56+
})
57+
58+
g.It("should have working validating webhook", func(ctx g.SpecContext) {
59+
g.By("creating a webhook test resource that will be rejected by the validating webhook")
60+
file := filepath.Join(webhookTestBaseDir, "webhook-test-validating-reject.yaml")
61+
_, err := applyResourceFileByPath(oc, file)
62+
o.Expect(err).To(o.HaveOccurred())
63+
64+
g.By("validating the error message")
65+
o.Expect(err.Error()).To(o.ContainSubstring("Invalid value: false: Spec.Valid must be true"))
66+
})
67+
68+
g.It("should have working mutating webhook", func(ctx g.SpecContext) {
69+
g.By("creating a valid webhook test resource")
70+
file := filepath.Join(webhookTestBaseDir, "webhook-test-accept.yaml")
71+
cleanup, err := applyResourceFileByPath(oc, file)
72+
g.DeferCleanup(cleanup)
73+
o.Expect(err).ToNot(o.HaveOccurred())
74+
75+
g.By("getting the created resource in v1 schema")
76+
obj, err := getWebhookTestResource(ctx, oc, "v1", "webhook-test")
77+
o.Expect(err).ToNot(o.HaveOccurred())
78+
o.Expect(obj).ToNot(o.BeNil())
79+
80+
g.By("validating the resource spec")
81+
spec := obj.Object["spec"].(map[string]interface{})
82+
o.Expect(spec).To(o.Equal(map[string]interface{}{
83+
"valid": true,
84+
"mutate": true,
85+
}))
86+
})
87+
88+
g.It("should have working conversion webhook", func(ctx g.SpecContext) {
89+
file := filepath.Join(webhookTestBaseDir, "webhook-test-accept.yaml")
90+
g.By("creating a valid webhook test resource")
91+
cleanup, err := applyResourceFileByPath(oc, file)
92+
g.DeferCleanup(cleanup)
93+
o.Expect(err).ToNot(o.HaveOccurred())
94+
95+
g.By("getting the created resource in v2 schema")
96+
obj, err := getWebhookTestResource(ctx, oc, "v2", "webhook-test")
97+
o.Expect(err).ToNot(o.HaveOccurred())
98+
o.Expect(obj).ToNot(o.BeNil())
99+
100+
g.By("validating the resource spec")
101+
spec := obj.Object["spec"].(map[string]interface{})
102+
o.Expect(spec).To(o.Equal(map[string]interface{}{
103+
"conversion": map[string]interface{}{
104+
"valid": true,
105+
"mutate": true,
106+
},
107+
}))
108+
})
109+
110+
g.It("should have cert secret", func(ctx g.SpecContext) {
111+
112+
})
113+
114+
g.It("should do one last thing for some reason", func(ctx g.SpecContext) {
115+
116+
})
117+
})
118+
119+
func installWebhookOperatorClusterCatalog(ctx g.SpecContext, oc *exutil.CLI) func() {
120+
webhookCatalogYaml := filepath.Join(webhookTestBaseDir, "webhook-operator-catalog.yaml")
121+
cleanup, err := applyResourceFileByPath(oc, webhookCatalogYaml)
122+
o.Expect(err).NotTo(o.HaveOccurred())
123+
124+
g.By("waiting for the webhook-operator ClusterCatalog to be serving")
125+
var lastReason string
126+
err = wait.PollUntilContextTimeout(ctx, 5*time.Second, 5*time.Minute, true,
127+
func(ctx context.Context) (bool, error) {
128+
isDone, err, status := checkWebhookCatalogServing(oc)
129+
if lastReason != status {
130+
g.GinkgoLogr.Info(fmt.Sprintf("waitForWebhookOperatorCatalogServing: %q", status))
131+
lastReason = status
132+
}
133+
return isDone, err
134+
})
135+
o.Expect(lastReason).To(o.BeEmpty())
136+
o.Expect(err).NotTo(o.HaveOccurred())
137+
return cleanup
138+
}
139+
140+
func installWebhookOperator(ctx g.SpecContext, oc *exutil.CLI) func() {
141+
file := filepath.Join(webhookTestBaseDir, "webhook-operator.yaml")
142+
cleanup, err := applyResourceFileByPath(oc, file)
143+
o.Expect(err).NotTo(o.HaveOccurred())
144+
145+
g.By("waiting for the webhook-operator bundle to be installed")
146+
var lastReason string
147+
err = wait.PollUntilContextTimeout(ctx, 5*time.Second, 5*time.Minute, true,
148+
func(ctx context.Context) (bool, error) {
149+
isDone, err, status := checkWebhookOperatorInstalled(oc)
150+
if lastReason != status {
151+
g.GinkgoLogr.Info(fmt.Sprintf("waitForWebhookOperatorInstalled: %q", status))
152+
lastReason = status
153+
}
154+
return isDone, err
155+
})
156+
o.Expect(lastReason).To(o.BeEmpty())
157+
o.Expect(err).NotTo(o.HaveOccurred())
158+
return cleanup
159+
}
160+
161+
func applyResourceFileByPath(oc *exutil.CLI, filePath string) (func(), error) {
162+
g.By(fmt.Sprintf("applying the necessary %q resources", filePath))
163+
err := oc.AsAdmin().WithoutNamespace().Run("apply").Args("-f", filePath).Execute()
164+
return func() {
165+
g.By(fmt.Sprintf("cleaning the necessary %q resources", filePath))
166+
err := oc.AsAdmin().WithoutNamespace().Run("delete").Args("-f", filePath).Execute()
167+
o.Expect(err).NotTo(o.HaveOccurred())
168+
}, err
169+
}
170+
171+
func checkWebhookCatalogServing(oc *exutil.CLI) (bool, error, string) {
172+
cmdArgs := []string{
173+
"clustercatalogs.olm.operatorframework.io",
174+
"webhook-operator-catalog",
175+
"-o=jsonpath={.status.conditions}",
176+
}
177+
178+
output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args(cmdArgs...).Output()
179+
if err != nil {
180+
return false, err, ""
181+
}
182+
// no data yet, so try again
183+
if output == "" {
184+
return false, nil, "no output"
185+
}
186+
187+
var conditions []metav1.Condition
188+
if err := json.Unmarshal([]byte(output), &conditions); err != nil {
189+
return false, fmt.Errorf("error in json.Unmarshal(%v): %v", output, err), ""
190+
}
191+
c := meta.FindStatusCondition(conditions, conditionTypeServing)
192+
if c == nil {
193+
return false, nil, fmt.Sprintf("condition not present: %q", conditionTypeServing)
194+
}
195+
if c.Status != metav1.ConditionTrue {
196+
return false, nil, fmt.Sprintf("expected status to be %q: %+v", metav1.ConditionTrue, c)
197+
}
198+
return true, nil, ""
199+
}
200+
201+
func checkWebhookOperatorInstalled(oc *exutil.CLI) (bool, error, string) {
202+
cmdArgs := []string{
203+
"clusterextensions.olm.operatorframework.io",
204+
"webhook-operator",
205+
"-o=jsonpath={.status.conditions}",
206+
}
207+
208+
output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args(cmdArgs...).Output()
209+
if err != nil {
210+
return false, err, ""
211+
}
212+
// no data yet, so try again
213+
if output == "" {
214+
return false, nil, "no output"
215+
}
216+
217+
var conditions []metav1.Condition
218+
if err := json.Unmarshal([]byte(output), &conditions); err != nil {
219+
return false, fmt.Errorf("error in json.Unmarshal(%v): %v", output, err), ""
220+
}
221+
c := meta.FindStatusCondition(conditions, conditionTypeInstalled)
222+
if c == nil {
223+
return false, nil, fmt.Sprintf("condition not present: %q", conditionTypeInstalled)
224+
}
225+
if c.Status != metav1.ConditionTrue {
226+
return false, nil, fmt.Sprintf("expected status to be %q: %+v", metav1.ConditionTrue, c)
227+
}
228+
return true, nil, ""
229+
}
230+
231+
func getWebhookTestResource(ctx g.SpecContext, oc *exutil.CLI, name, version string) (*unstructured.Unstructured, error) {
232+
return getResource(ctx, oc, fmt.Sprintf("webhooktests.%s.webhook.operators.coreos.io", version), "webhook-operator", name)
233+
}
234+
235+
func getResource(ctx g.SpecContext, oc *exutil.CLI, kind, namespace, name string) (*unstructured.Unstructured, error) {
236+
var obj *unstructured.Unstructured
237+
return obj, wait.PollUntilContextTimeout(ctx, 5*time.Second, 5*time.Minute, true,
238+
func(ctx context.Context) (bool, error) {
239+
cmdArgs := []string{
240+
kind,
241+
name,
242+
fmt.Sprintf("--namespace='%s'", namespace),
243+
"-o=json",
244+
}
245+
246+
output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args(cmdArgs...).Output()
247+
if err != nil {
248+
g.GinkgoLogr.Info(fmt.Sprintf("error getting resource kind='%s' namespace='%s' name='%s': %q", kind, namespace, name, err))
249+
return false, err
250+
}
251+
if err := json.Unmarshal([]byte(output), obj); err != nil {
252+
g.GinkgoLogr.Info(fmt.Sprintf("error unmarshalling kind='%s' namespace='%s' name='%s': %q", kind, namespace, name, err))
253+
return false, fmt.Errorf("error in json.Unmarshal(%v): %v", output, err)
254+
}
255+
return true, nil
256+
})
257+
}

0 commit comments

Comments
 (0)