github.com/cilium/cilium@v1.16.2/operator/pkg/gateway-api/routechecks/route_checks.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package routechecks
     5  
     6  import (
     7  	corev1 "k8s.io/api/core/v1"
     8  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	"sigs.k8s.io/controller-runtime/pkg/client"
    11  	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
    12  	gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
    13  
    14  	"github.com/cilium/cilium/operator/pkg/gateway-api/helpers"
    15  )
    16  
    17  func CheckAgainstCrossNamespaceBackendReferences(input Input) (bool, error) {
    18  	continueChecks := true
    19  
    20  	for _, rule := range input.GetRules() {
    21  		for _, be := range rule.GetBackendRefs() {
    22  			ns := helpers.NamespaceDerefOr(be.Namespace, input.GetNamespace())
    23  
    24  			if ns != input.GetNamespace() && !helpers.IsBackendReferenceAllowed(input.GetNamespace(), be, input.GetGVK(), input.GetGrants()) {
    25  				// no reference grants, update the status for all the parents
    26  				input.SetAllParentCondition(metav1.Condition{
    27  					Type:    string(gatewayv1.RouteConditionResolvedRefs),
    28  					Status:  metav1.ConditionFalse,
    29  					Reason:  string(gatewayv1.RouteReasonRefNotPermitted),
    30  					Message: "Cross namespace references are not allowed",
    31  				})
    32  
    33  				continueChecks = false
    34  			}
    35  		}
    36  	}
    37  	return continueChecks, nil
    38  }
    39  
    40  func CheckBackend(input Input) (bool, error) {
    41  	continueChecks := true
    42  
    43  	for _, rule := range input.GetRules() {
    44  		for _, be := range rule.GetBackendRefs() {
    45  			if !helpers.IsService(be.BackendObjectReference) && !helpers.IsServiceImport(be.BackendObjectReference) {
    46  				input.SetAllParentCondition(metav1.Condition{
    47  					Type:    string(gatewayv1alpha2.RouteConditionResolvedRefs),
    48  					Status:  metav1.ConditionFalse,
    49  					Reason:  string(gatewayv1.RouteReasonInvalidKind),
    50  					Message: "Unsupported backend kind " + string(*be.Kind),
    51  				})
    52  
    53  				continueChecks = false
    54  				continue
    55  			}
    56  			if be.BackendObjectReference.Port == nil {
    57  				input.SetAllParentCondition(metav1.Condition{
    58  					Type:    string(gatewayv1alpha2.RouteConditionResolvedRefs),
    59  					Status:  metav1.ConditionFalse,
    60  					Reason:  string(gatewayv1.RouteReasonInvalidKind),
    61  					Message: "Must have port for backend object reference",
    62  				})
    63  
    64  				continueChecks = false
    65  				continue
    66  			}
    67  		}
    68  	}
    69  
    70  	return continueChecks, nil
    71  }
    72  
    73  func CheckHasServiceImportSupport(input Input) (bool, error) {
    74  	for _, rule := range input.GetRules() {
    75  		for _, be := range rule.GetBackendRefs() {
    76  			if !helpers.IsServiceImport(be.BackendObjectReference) {
    77  				continue
    78  			}
    79  
    80  			if !helpers.HasServiceImportSupport(input.GetClient().Scheme()) {
    81  				input.SetAllParentCondition(metav1.Condition{
    82  					Type:   string(gatewayv1.RouteConditionResolvedRefs),
    83  					Status: metav1.ConditionFalse,
    84  					Reason: string(gatewayv1.RouteReasonBackendNotFound),
    85  					Message: "Attempt to reference a ServiceImport backend while " +
    86  						"the corresponding CRD is not installed, " +
    87  						"please restart the cilium-operator if the CRD is already installed",
    88  				})
    89  				return false, nil
    90  			}
    91  			return true, nil
    92  		}
    93  	}
    94  
    95  	return true, nil
    96  }
    97  
    98  func CheckBackendIsExistingService(input Input) (bool, error) {
    99  	for _, rule := range input.GetRules() {
   100  		for _, be := range rule.GetBackendRefs() {
   101  			ns := helpers.NamespaceDerefOr(be.Namespace, input.GetNamespace())
   102  			svcName, err := helpers.GetBackendServiceName(input.GetClient(), ns, be.BackendObjectReference)
   103  			if err != nil {
   104  				// Service Import does not exist, update the status for all the parents
   105  				// The `Accepted` condition on a route only describes whether
   106  				// the route attached successfully to its parent, so no error
   107  				// is returned here, so that the next validation can be run.
   108  				input.SetAllParentCondition(metav1.Condition{
   109  					Type:    string(gatewayv1.RouteConditionResolvedRefs),
   110  					Status:  metav1.ConditionFalse,
   111  					Reason:  string(gatewayv1.RouteReasonBackendNotFound),
   112  					Message: err.Error(),
   113  				})
   114  				continue
   115  			}
   116  			svc := &corev1.Service{}
   117  			if err := input.GetClient().Get(input.GetContext(), client.ObjectKey{Name: svcName, Namespace: ns}, svc); err != nil {
   118  				if !k8serrors.IsNotFound(err) {
   119  					input.Log().WithError(err).Error("Failed to get Service")
   120  					return false, err
   121  				}
   122  				// Service does not exist, update the status for all the parents
   123  				// The `Accepted` condition on a route only describes whether
   124  				// the route attached successfully to its parent, so no error
   125  				// is returned here, so that the next validation can be run.
   126  				input.SetAllParentCondition(metav1.Condition{
   127  					Type:    string(gatewayv1.RouteConditionResolvedRefs),
   128  					Status:  metav1.ConditionFalse,
   129  					Reason:  string(gatewayv1.RouteReasonBackendNotFound),
   130  					Message: err.Error(),
   131  				})
   132  			}
   133  		}
   134  	}
   135  
   136  	return true, nil
   137  }