1
16
17 package cleaner
18
19 import (
20 "context"
21 "testing"
22 "time"
23
24 capi "k8s.io/api/certificates/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/client-go/kubernetes/fake"
27 )
28
29 const (
30 expiredCert = `-----BEGIN CERTIFICATE-----
31 MIICIzCCAc2gAwIBAgIJAOApTlMFDOUnMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
32 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
33 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD
34 VQQDDAEqMB4XDTE3MTAwNDIwNDgzOFoXDTE3MTAwMzIwNDgzOFowbTELMAkGA1UE
35 BhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9uZG9uMRgwFgYDVQQK
36 DA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxCjAIBgNV
37 BAMMASowXDANBgkqhkiG9w0BAQEFAANLADBIAkEA3Gt0KmuRXDxvqZUiX/xqAn1t
38 nZZX98guZvPPyxnQtV3YpA274W0sX3jL+U71Ya+3kaUstXQa4YrWBUHiXoqJnwID
39 AQABo1AwTjAdBgNVHQ4EFgQUtDsIpzHoUiLsO88f9fm+G0tYSPowHwYDVR0jBBgw
40 FoAUtDsIpzHoUiLsO88f9fm+G0tYSPowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
41 AQsFAANBADfrlKof5CUkxGlX9Rifxv/mWOk8ZuTLWfMYQH2nycBHnmOxy6sR+87W
42 /Mb/uRz0TXVnGVcbu5E8Bz7e/Far1ZI=
43 -----END CERTIFICATE-----`
44 unexpiredCert = `-----BEGIN CERTIFICATE-----
45 MIICJTCCAc+gAwIBAgIJAIRjMToP+pPEMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
46 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
47 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD
48 VQQDDAEqMCAXDTE3MTAwNDIwNDUyNFoYDzIxMTcwOTEwMjA0NTI0WjBtMQswCQYD
49 VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV
50 BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEKMAgG
51 A1UEAwwBKjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7j9BAV5HqIJGi6r4G4YeI
52 ioHxH2loVu8IOKSK7xVs3v/EjR/eXbQzM+jZU7duyZqn6YjySZNLl0K0MfHCHBgX
53 AgMBAAGjUDBOMB0GA1UdDgQWBBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAfBgNVHSME
54 GDAWgBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
55 DQEBCwUAA0EALDi9OidANHflx8q+w3p0rJo9gpA6cJcFpEtP2Lv4kvOtB1f6L0jY
56 MLd7MVm4cS/MNcx4L7l23UC3Hx4+nAxvIg==
57 -----END CERTIFICATE-----`
58 )
59
60 func TestCleanerWithApprovedExpiredCSR(t *testing.T) {
61 testCases := []struct {
62 name string
63 created metav1.Time
64 certificate []byte
65 conditions []capi.CertificateSigningRequestCondition
66 expectedActions []string
67 }{
68 {
69 "no delete approved not passed deadline",
70 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
71 []byte(unexpiredCert),
72 []capi.CertificateSigningRequestCondition{
73 {
74 Type: capi.CertificateApproved,
75 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
76 },
77 },
78 []string{},
79 },
80 {
81 "no delete approved passed deadline not issued",
82 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
83 nil,
84 []capi.CertificateSigningRequestCondition{
85 {
86 Type: capi.CertificateApproved,
87 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
88 },
89 },
90 []string{},
91 },
92 {
93 "delete approved passed deadline",
94 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
95 []byte(unexpiredCert),
96 []capi.CertificateSigningRequestCondition{
97 {
98 Type: capi.CertificateApproved,
99 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
100 },
101 },
102 []string{"delete"},
103 },
104 {
105 "no delete denied not passed deadline",
106 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
107 nil,
108 []capi.CertificateSigningRequestCondition{
109 {
110 Type: capi.CertificateDenied,
111 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
112 },
113 },
114 []string{},
115 },
116 {
117 "delete denied passed deadline",
118 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
119 nil,
120 []capi.CertificateSigningRequestCondition{
121 {
122 Type: capi.CertificateDenied,
123 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
124 },
125 },
126 []string{"delete"},
127 },
128 {
129 "no delete failed not passed deadline",
130 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
131 nil,
132 []capi.CertificateSigningRequestCondition{
133 {
134 Type: capi.CertificateApproved,
135 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
136 },
137 {
138 Type: capi.CertificateFailed,
139 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
140 },
141 },
142 []string{},
143 },
144 {
145 "delete failed passed deadline",
146 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
147 nil,
148 []capi.CertificateSigningRequestCondition{
149 {
150 Type: capi.CertificateApproved,
151 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
152 },
153 {
154 Type: capi.CertificateFailed,
155 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
156 },
157 },
158 []string{"delete"},
159 },
160 {
161 "no delete pending not passed deadline",
162 metav1.NewTime(time.Now().Add(-5 * time.Hour)),
163 nil,
164 []capi.CertificateSigningRequestCondition{},
165 []string{},
166 },
167 {
168 "delete pending passed deadline",
169 metav1.NewTime(time.Now().Add(-25 * time.Hour)),
170 nil,
171 []capi.CertificateSigningRequestCondition{},
172 []string{"delete"},
173 },
174 {
175 "no delete approved not passed deadline unexpired",
176 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
177 []byte(unexpiredCert),
178 []capi.CertificateSigningRequestCondition{
179 {
180 Type: capi.CertificateApproved,
181 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
182 },
183 },
184 []string{},
185 },
186 {
187 "delete approved not passed deadline expired",
188 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
189 []byte(expiredCert),
190 []capi.CertificateSigningRequestCondition{
191 {
192 Type: capi.CertificateApproved,
193 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)),
194 },
195 },
196 []string{"delete"},
197 },
198 {
199 "delete approved passed deadline unparseable",
200 metav1.NewTime(time.Now().Add(-1 * time.Minute)),
201 []byte(`garbage`),
202 []capi.CertificateSigningRequestCondition{
203 {
204 Type: capi.CertificateApproved,
205 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)),
206 },
207 },
208 []string{"delete"},
209 },
210 }
211
212 for _, tc := range testCases {
213 t.Run(tc.name, func(t *testing.T) {
214 csr := &capi.CertificateSigningRequest{
215 ObjectMeta: metav1.ObjectMeta{
216 Name: "fake-csr",
217 CreationTimestamp: tc.created,
218 },
219 Status: capi.CertificateSigningRequestStatus{
220 Certificate: tc.certificate,
221 Conditions: tc.conditions,
222 },
223 }
224
225 client := fake.NewSimpleClientset(csr)
226 s := &CSRCleanerController{
227 csrClient: client.CertificatesV1().CertificateSigningRequests(),
228 }
229 ctx := context.TODO()
230 err := s.handle(ctx, csr)
231 if err != nil {
232 t.Fatalf("failed to clean CSR: %v", err)
233 }
234
235 actions := client.Actions()
236 if len(actions) != len(tc.expectedActions) {
237 t.Fatalf("got %d actions, wanted %d actions", len(actions), len(tc.expectedActions))
238 }
239 for i := 0; i < len(actions); i++ {
240 if a := actions[i]; !a.Matches(tc.expectedActions[i], "certificatesigningrequests") {
241 t.Errorf("got action %#v, wanted %v", a, tc.expectedActions[i])
242 }
243 }
244 })
245 }
246 }
247
View as plain text