| /* |
| Copyright 2017 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package cleaner |
| |
| import ( |
| "testing" |
| "time" |
| |
| capi "k8s.io/api/certificates/v1beta1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/client-go/kubernetes/fake" |
| ) |
| |
| const ( |
| expiredCert = `-----BEGIN CERTIFICATE----- |
| MIICIzCCAc2gAwIBAgIJAOApTlMFDOUnMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV |
| BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE |
| CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD |
| VQQDDAEqMB4XDTE3MTAwNDIwNDgzOFoXDTE3MTAwMzIwNDgzOFowbTELMAkGA1UE |
| BhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9uZG9uMRgwFgYDVQQK |
| DA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxCjAIBgNV |
| BAMMASowXDANBgkqhkiG9w0BAQEFAANLADBIAkEA3Gt0KmuRXDxvqZUiX/xqAn1t |
| nZZX98guZvPPyxnQtV3YpA274W0sX3jL+U71Ya+3kaUstXQa4YrWBUHiXoqJnwID |
| AQABo1AwTjAdBgNVHQ4EFgQUtDsIpzHoUiLsO88f9fm+G0tYSPowHwYDVR0jBBgw |
| FoAUtDsIpzHoUiLsO88f9fm+G0tYSPowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B |
| AQsFAANBADfrlKof5CUkxGlX9Rifxv/mWOk8ZuTLWfMYQH2nycBHnmOxy6sR+87W |
| /Mb/uRz0TXVnGVcbu5E8Bz7e/Far1ZI= |
| -----END CERTIFICATE-----` |
| unexpiredCert = `-----BEGIN CERTIFICATE----- |
| MIICJTCCAc+gAwIBAgIJAIRjMToP+pPEMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV |
| BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE |
| CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD |
| VQQDDAEqMCAXDTE3MTAwNDIwNDUyNFoYDzIxMTcwOTEwMjA0NTI0WjBtMQswCQYD |
| VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV |
| BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEKMAgG |
| A1UEAwwBKjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7j9BAV5HqIJGi6r4G4YeI |
| ioHxH2loVu8IOKSK7xVs3v/EjR/eXbQzM+jZU7duyZqn6YjySZNLl0K0MfHCHBgX |
| AgMBAAGjUDBOMB0GA1UdDgQWBBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAfBgNVHSME |
| GDAWgBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 |
| DQEBCwUAA0EALDi9OidANHflx8q+w3p0rJo9gpA6cJcFpEtP2Lv4kvOtB1f6L0jY |
| MLd7MVm4cS/MNcx4L7l23UC3Hx4+nAxvIg== |
| -----END CERTIFICATE-----` |
| ) |
| |
| func TestCleanerWithApprovedExpiredCSR(t *testing.T) { |
| testCases := []struct { |
| name string |
| created metav1.Time |
| certificate []byte |
| conditions []capi.CertificateSigningRequestCondition |
| expectedActions []string |
| }{ |
| { |
| "no delete approved not passed deadline", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| []byte(unexpiredCert), |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateApproved, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), |
| }, |
| }, |
| []string{}, |
| }, |
| { |
| "no delete approved passed deadline not issued", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| nil, |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateApproved, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), |
| }, |
| }, |
| []string{}, |
| }, |
| { |
| "delete approved passed deadline", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| []byte(unexpiredCert), |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateApproved, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), |
| }, |
| }, |
| []string{"delete"}, |
| }, |
| { |
| "no delete denied not passed deadline", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| nil, |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateDenied, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), |
| }, |
| }, |
| []string{}, |
| }, |
| { |
| "delete denied passed deadline", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| nil, |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateDenied, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), |
| }, |
| }, |
| []string{"delete"}, |
| }, |
| { |
| "no delete pending not passed deadline", |
| metav1.NewTime(time.Now().Add(-5 * time.Hour)), |
| nil, |
| []capi.CertificateSigningRequestCondition{}, |
| []string{}, |
| }, |
| { |
| "delete pending passed deadline", |
| metav1.NewTime(time.Now().Add(-25 * time.Hour)), |
| nil, |
| []capi.CertificateSigningRequestCondition{}, |
| []string{"delete"}, |
| }, |
| { |
| "no delete approved not passed deadline unexpired", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| []byte(unexpiredCert), |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateApproved, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), |
| }, |
| }, |
| []string{}, |
| }, |
| { |
| "delete approved not passed deadline expired", |
| metav1.NewTime(time.Now().Add(-1 * time.Minute)), |
| []byte(expiredCert), |
| []capi.CertificateSigningRequestCondition{ |
| { |
| Type: capi.CertificateApproved, |
| LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), |
| }, |
| }, |
| []string{"delete"}, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| t.Run(tc.name, func(t *testing.T) { |
| csr := &capi.CertificateSigningRequest{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "fake-csr", |
| CreationTimestamp: tc.created, |
| }, |
| Status: capi.CertificateSigningRequestStatus{ |
| Certificate: tc.certificate, |
| Conditions: tc.conditions, |
| }, |
| } |
| |
| client := fake.NewSimpleClientset(csr) |
| s := &CSRCleanerController{ |
| csrClient: client.CertificatesV1beta1().CertificateSigningRequests(), |
| } |
| |
| err := s.handle(csr) |
| if err != nil { |
| t.Fatalf("failed to clean CSR: %v", err) |
| } |
| |
| actions := client.Actions() |
| if len(actions) != len(tc.expectedActions) { |
| t.Fatalf("got %d actions, wanted %d actions", len(actions), len(tc.expectedActions)) |
| } |
| for i := 0; i < len(actions); i++ { |
| if a := actions[i]; !a.Matches(tc.expectedActions[i], "certificatesigningrequests") { |
| t.Errorf("got action %#v, wanted %v", a, tc.expectedActions[i]) |
| } |
| } |
| }) |
| } |
| } |