github.com/cilium/cilium@v1.16.2/pkg/egressgateway/helpers_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package egressgateway
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"net/netip"
    10  	"testing"
    11  
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/runtime"
    14  	"k8s.io/apimachinery/pkg/types"
    15  
    16  	v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    17  	"github.com/cilium/cilium/pkg/k8s/resource"
    18  	slimv1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    19  	k8sTypes "github.com/cilium/cilium/pkg/k8s/types"
    20  	"github.com/cilium/cilium/pkg/policy/api"
    21  )
    22  
    23  type fakeResource[T runtime.Object] chan resource.Event[T]
    24  
    25  func (fr fakeResource[T]) sync(tb testing.TB) {
    26  	var sync resource.Event[T]
    27  	sync.Kind = resource.Sync
    28  	fr.process(tb, sync)
    29  }
    30  
    31  func (fr fakeResource[T]) process(tb testing.TB, ev resource.Event[T]) {
    32  	tb.Helper()
    33  	if err := fr.processWithError(ev); err != nil {
    34  		tb.Fatal("Failed to process event:", err)
    35  	}
    36  }
    37  
    38  func (fr fakeResource[T]) processWithError(ev resource.Event[T]) error {
    39  	errs := make(chan error)
    40  	ev.Done = func(err error) {
    41  		errs <- err
    42  	}
    43  	fr <- ev
    44  	return <-errs
    45  }
    46  
    47  func (fr fakeResource[T]) Observe(ctx context.Context, next func(event resource.Event[T]), complete func(error)) {
    48  	complete(errors.New("not implemented"))
    49  }
    50  
    51  func (fr fakeResource[T]) Events(ctx context.Context, opts ...resource.EventsOpt) <-chan resource.Event[T] {
    52  	if len(opts) > 1 {
    53  		// Ideally we'd only ignore resource.WithRateLimit here, but that
    54  		// isn't possible.
    55  		panic("more than one option is not supported")
    56  	}
    57  	return fr
    58  }
    59  
    60  func (fr fakeResource[T]) Store(context.Context) (resource.Store[T], error) {
    61  	return nil, errors.New("not implemented")
    62  }
    63  
    64  func addPolicy(tb testing.TB, policies fakeResource[*Policy], params *policyParams) {
    65  	tb.Helper()
    66  
    67  	policy, _ := newCEGP(params)
    68  	policies.process(tb, resource.Event[*Policy]{
    69  		Kind:   resource.Upsert,
    70  		Object: policy,
    71  	})
    72  }
    73  
    74  type policyParams struct {
    75  	name            string
    76  	endpointLabels  map[string]string
    77  	destinationCIDR string
    78  	excludedCIDRs   []string
    79  	nodeLabels      map[string]string
    80  	iface           string
    81  	egressIP        string
    82  }
    83  
    84  func newCEGP(params *policyParams) (*v2.CiliumEgressGatewayPolicy, *PolicyConfig) {
    85  	parsedDestinationCIDR, _ := netip.ParsePrefix(params.destinationCIDR)
    86  
    87  	parsedExcludedCIDRs := make([]netip.Prefix, 0, len(params.excludedCIDRs))
    88  	for _, excludedCIDR := range params.excludedCIDRs {
    89  		parsedExcludedCIDR, _ := netip.ParsePrefix(excludedCIDR)
    90  		parsedExcludedCIDRs = append(parsedExcludedCIDRs, parsedExcludedCIDR)
    91  	}
    92  
    93  	addr, _ := netip.ParseAddr(params.egressIP)
    94  	policy := &PolicyConfig{
    95  		id: types.NamespacedName{
    96  			Name: params.name,
    97  		},
    98  		dstCIDRs:      []netip.Prefix{parsedDestinationCIDR},
    99  		excludedCIDRs: parsedExcludedCIDRs,
   100  		endpointSelectors: []api.EndpointSelector{
   101  			{
   102  				LabelSelector: &slimv1.LabelSelector{
   103  					MatchLabels: params.endpointLabels,
   104  				},
   105  			},
   106  		},
   107  		policyGwConfig: &policyGatewayConfig{
   108  			iface:    params.iface,
   109  			egressIP: addr,
   110  		},
   111  	}
   112  
   113  	if len(params.endpointLabels) != 0 {
   114  		policy.endpointSelectors = []api.EndpointSelector{
   115  			{
   116  				LabelSelector: &slimv1.LabelSelector{
   117  					MatchLabels: params.endpointLabels,
   118  				},
   119  			},
   120  		}
   121  	}
   122  
   123  	if len(params.nodeLabels) != 0 {
   124  		policy.policyGwConfig.nodeSelector = api.EndpointSelector{
   125  			LabelSelector: &slimv1.LabelSelector{
   126  				MatchLabels: params.nodeLabels,
   127  			},
   128  		}
   129  	}
   130  
   131  	excludedCIDRs := []v2.IPv4CIDR{}
   132  	for _, excludedCIDR := range params.excludedCIDRs {
   133  		excludedCIDRs = append(excludedCIDRs, v2.IPv4CIDR(excludedCIDR))
   134  	}
   135  
   136  	cegp := &v2.CiliumEgressGatewayPolicy{
   137  		ObjectMeta: metav1.ObjectMeta{
   138  			Name: params.name,
   139  		},
   140  		Spec: v2.CiliumEgressGatewayPolicySpec{
   141  			Selectors: []v2.EgressRule{
   142  				{
   143  					PodSelector: &slimv1.LabelSelector{
   144  						MatchLabels: params.endpointLabels,
   145  					},
   146  				},
   147  			},
   148  			DestinationCIDRs: []v2.IPv4CIDR{
   149  				v2.IPv4CIDR(params.destinationCIDR),
   150  			},
   151  			ExcludedCIDRs: excludedCIDRs,
   152  			EgressGateway: &v2.EgressGateway{
   153  				NodeSelector: &slimv1.LabelSelector{
   154  					MatchLabels: params.nodeLabels,
   155  				},
   156  				Interface: params.iface,
   157  				EgressIP:  params.egressIP,
   158  			},
   159  		},
   160  	}
   161  
   162  	return cegp, policy
   163  }
   164  
   165  func addEndpoint(tb testing.TB, endpoints fakeResource[*k8sTypes.CiliumEndpoint], ep *k8sTypes.CiliumEndpoint) {
   166  	endpoints.process(tb, resource.Event[*k8sTypes.CiliumEndpoint]{
   167  		Kind:   resource.Upsert,
   168  		Object: ep,
   169  	})
   170  }
   171  
   172  func deleteEndpoint(tb testing.TB, endpoints fakeResource[*k8sTypes.CiliumEndpoint], ep *k8sTypes.CiliumEndpoint) {
   173  	endpoints.process(tb, resource.Event[*k8sTypes.CiliumEndpoint]{
   174  		Kind:   resource.Delete,
   175  		Object: ep,
   176  	})
   177  }