github.com/verrazzano/verrazzano@v1.7.0/pkg/k8s/ready/certificates.go (about)

     1  // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  package ready
     4  
     5  import (
     6  	"context"
     7  	"github.com/verrazzano/verrazzano/pkg/vzcr"
     8  	"sort"
     9  
    10  	certapiv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    11  	cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
    12  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    13  	vzapi "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    14  	"k8s.io/apimachinery/pkg/api/errors"
    15  	"k8s.io/apimachinery/pkg/types"
    16  	clipkg "sigs.k8s.io/controller-runtime/pkg/client"
    17  )
    18  
    19  // CertificatesAreReady Checks the list of named objects to see if there are matching
    20  // Cert-Manager Certificate objects, and checks if those are in a Ready state.
    21  //
    22  // ctx				A valid ComponentContext for the operation
    23  // certificates		A list of NamespacedNames; this should be names of expected Certificate objects
    24  //
    25  // Returns true and an empty list of names if all certs are ready, false and a list of certificate names that are
    26  // NOT in the ready state
    27  func CertificatesAreReady(client clipkg.Client, log vzlog.VerrazzanoLogger, vz *vzapi.Verrazzano, certificates []types.NamespacedName) (ready bool, certsNotReady []types.NamespacedName) {
    28  	if len(certificates) == 0 {
    29  		return true, []types.NamespacedName{}
    30  	}
    31  
    32  	if !vzcr.IsClusterIssuerEnabled(vz) {
    33  		log.Oncef("Cert-Manager ClusterIssuer disabled, skipping certificates check")
    34  		return true, []types.NamespacedName{}
    35  	}
    36  
    37  	log.Oncef("Checking certificates status for %v", certificates)
    38  	for _, name := range certificates {
    39  		ready, err := IsCertficateIsReady(log, client, name)
    40  		if err != nil {
    41  			log.Errorf("Error getting certificate %s: %s", name, err)
    42  		}
    43  		if !ready {
    44  			certsNotReady = append(certsNotReady, name)
    45  		}
    46  	}
    47  	return len(certsNotReady) == 0, certsNotReady
    48  }
    49  
    50  // IsCertficateIsReady Checks if a Cert-Manager Certificate object with the specified NamespacedName
    51  // can be found in the cluster, and if it is in a Ready state.
    52  //
    53  // Returns
    54  // - true/nil if a matching Certificate object is found and Ready
    55  // - false/nil if a matching Certifiate object is found and not Ready
    56  // - false/error if an unexpected error has occurred
    57  func IsCertficateIsReady(log vzlog.VerrazzanoLogger, client clipkg.Client, name types.NamespacedName) (bool, error) {
    58  	cert := &certapiv1.Certificate{}
    59  	if err := client.Get(context.TODO(), name, cert); err != nil {
    60  		if errors.IsNotFound(err) {
    61  			return false, nil
    62  		}
    63  		return false, err
    64  	}
    65  	certConditions := cert.Status.Conditions
    66  	if len(certConditions) > 0 {
    67  		if len(certConditions) > 1 {
    68  			// Typically, I've only seen one condition in the Certificate object, but if there's
    69  			// more than one sort the copy so the most recent is first
    70  			sort.Slice(certConditions, func(i, j int) bool {
    71  				return certConditions[i].LastTransitionTime.After(
    72  					certConditions[j].LastTransitionTime.Time)
    73  			})
    74  		}
    75  		mostRecent := certConditions[0]
    76  		if mostRecent.Status == cmmeta.ConditionTrue && mostRecent.Type == certapiv1.CertificateConditionReady {
    77  			return true, nil
    78  		}
    79  		log.Progressf("Certificate %s not ready, reason: %s, message: %s", name, mostRecent.Reason, mostRecent.Message)
    80  	}
    81  	return false, nil
    82  }