Skip to content

Commit 33b1d97

Browse files
committed
Add test for ocpbugs-60628
1 parent 53e01e4 commit 33b1d97

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

test/extended/main.go

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,147 @@
11
package extended
22

33
import (
4+
"context"
5+
"encoding/base64"
6+
"fmt"
7+
"time"
8+
49
g "github.com/onsi/ginkgo/v2"
510
o "github.com/onsi/gomega"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/client-go/kubernetes"
13+
"k8s.io/utils/ptr"
14+
15+
exutil "github.com/openshift/origin/test/extended/util"
616
)
717

818
var _ = g.Describe("[Jira:kube-apiserver][sig-api-machinery] sanity test", func() {
919
g.It("should always pass [Suite:openshift/cluster-kube-apiserver-operator/conformance/parallel]", func() {
1020
o.Expect(true).To(o.BeTrue())
1121
})
1222
})
23+
24+
// Helper: scale a Deployment
25+
func scaleDeployment(oc *exutil.CLI, ns, name string, replicas int32) {
26+
_, err := oc.AdminKubeClient().AppsV1().Deployments(ns).
27+
Patch(context.Background(), name,
28+
metav1.TypeMergePatchType,
29+
[]byte(fmt.Sprintf(`{"spec":{"replicas":%d}}`, replicas)),
30+
metav1.PatchOptions{})
31+
o.Expect(err).NotTo(o.HaveOccurred())
32+
}
33+
34+
// Helper: patch annotations on a Secret/ConfigMap
35+
func patchAnnotationsOnSecret(oc *exutil.CLI, ns, name string, anns map[string]*string) {
36+
patch := `{"metadata":{"annotations":{`
37+
first := true
38+
for k, v := range anns {
39+
if !first {
40+
patch += ","
41+
}
42+
if v == nil {
43+
patch += fmt.Sprintf("%q:null", k)
44+
} else {
45+
patch += fmt.Sprintf("%q:%q", k, *v)
46+
}
47+
first = false
48+
}
49+
patch += "}}}"
50+
_, err := oc.AdminKubeClient().CoreV1().Secrets(ns).
51+
Patch(context.Background(), name,
52+
metav1.TypeMergePatchType, []byte(patch), metav1.PatchOptions{})
53+
o.Expect(err).NotTo(o.HaveOccurred())
54+
}
55+
56+
var _ = g.Describe("[sig-api-machinery][cert-rotation][sidecar-refresh-only-when-expired] merged scenarios", func() {
57+
defer g.GinkgoRecover()
58+
oc := exutil.NewCLI("cert-rotation").AsAdmin()
59+
60+
ns := "openshift-kube-apiserver"
61+
secretName := "kubelet-client"
62+
63+
var kc *kubernetes.Clientset
64+
g.BeforeEach(func() {
65+
kc = oc.AdminKubeClient()
66+
})
67+
68+
g.It("pauses CVO, tests sidecar/operator behavior, then resumes CVO", func() {
69+
ctx := context.Background()
70+
71+
// --- Pause CVO
72+
g.By("Pausing CVO reconciliation")
73+
scaleDeployment(oc, "openshift-cluster-version", "cluster-version-operator", 0)
74+
_, err := oc.AdminConfigClient().ConfigV1().ClusterVersions().
75+
Patch(ctx, "version", metav1.TypeMergePatchType,
76+
[]byte(`{"spec":{"overrides":[{"kind":"Deployment","group":"apps","namespace":"openshift-cluster-version","name":"cluster-version-operator","unmanaged":true}]}}`),
77+
metav1.PatchOptions{})
78+
o.Expect(err).NotTo(o.HaveOccurred())
79+
80+
defer func() {
81+
// --- Resume CVO
82+
g.By("Resuming CVO reconciliation")
83+
scaleDeployment(oc, "openshift-cluster-version", "cluster-version-operator", 1)
84+
_, _ = oc.AdminConfigClient().ConfigV1().ClusterVersions().
85+
Patch(ctx, "version", metav1.TypeMergePatchType,
86+
[]byte(`{"spec":{"overrides":[]}}`), metav1.PatchOptions{})
87+
}()
88+
89+
// --- Scenario A
90+
g.By("Scenario A: operator down, removing metadata should not be re-added by sidecar")
91+
scaleDeployment(oc, "openshift-kube-apiserver-operator", "openshift-kube-apiserver-operator", 0)
92+
93+
sec, err := kc.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
94+
o.Expect(err).NotTo(o.HaveOccurred())
95+
dataBefore := base64.StdEncoding.EncodeToString(sec.Data["tls.crt"])
96+
97+
patchAnnotationsOnSecret(oc, ns, secretName, map[string]*string{
98+
"auth.openshift.io/component": nil,
99+
"auth.openshift.io/description": nil,
100+
})
101+
102+
o.Consistently(func() bool {
103+
s, _ := kc.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
104+
ann := s.Annotations
105+
_, comp := ann["auth.openshift.io/component"]
106+
_, desc := ann["auth.openshift.io/description"]
107+
dataNow := base64.StdEncoding.EncodeToString(s.Data["tls.crt"])
108+
return !comp && !desc && dataNow == dataBefore
109+
}, 2*time.Minute, 10*time.Second).Should(o.BeTrue())
110+
111+
// --- Scenario B
112+
g.By("Scenario B: operator up, metadata restored without cert rotation")
113+
scaleDeployment(oc, "openshift-kube-apiserver-operator", "openshift-kube-apiserver-operator", 1)
114+
115+
o.Eventually(func() bool {
116+
s, _ := kc.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
117+
ann := s.Annotations
118+
comp := ann["auth.openshift.io/component"] != ""
119+
desc := ann["auth.openshift.io/description"] != ""
120+
dataNow := base64.StdEncoding.EncodeToString(s.Data["tls.crt"])
121+
return comp && desc && dataNow == dataBefore
122+
}, 3*time.Minute, 10*time.Second).Should(o.BeTrue())
123+
124+
// --- Scenario C
125+
g.By("Scenario C: operator down, expired not-after triggers sidecar rotation")
126+
scaleDeployment(oc, "openshift-kube-apiserver-operator", "openshift-kube-apiserver-operator", 0)
127+
past := "2000-01-01T00:00:00Z"
128+
patchAnnotationsOnSecret(oc, ns, secretName, map[string]*string{
129+
"auth.openshift.io/not-after": ptr.To(past),
130+
})
131+
132+
o.Eventually(func() bool {
133+
s, _ := kc.CoreV1().Secrets(ns).Get(ctx, secretName, metav1.GetOptions{})
134+
dataNow := base64.StdEncoding.EncodeToString(s.Data["tls.crt"])
135+
ann := s.Annotations
136+
na := ann["auth.openshift.io/not-after"]
137+
if na == "" {
138+
return false
139+
}
140+
// content rotated
141+
return dataNow != dataBefore
142+
}, 3*time.Minute, 10*time.Second).Should(o.BeTrue())
143+
144+
// scale operator back up for cleanup
145+
scaleDeployment(oc, "openshift-kube-apiserver-operator", "openshift-kube-apiserver-operator", 1)
146+
})
147+
})

0 commit comments

Comments
 (0)