github.com/cilium/cilium@v1.16.2/pkg/policy/api/egress_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package api
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/netip"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"k8s.io/apimachinery/pkg/util/intstr"
    14  
    15  	slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    16  )
    17  
    18  func TestRequiresDerivativeRuleWithoutToGroups(t *testing.T) {
    19  	eg := EgressRule{}
    20  	require.Equal(t, false, eg.RequiresDerivative())
    21  }
    22  
    23  func TestRequiresDerivativeRuleWithToGroups(t *testing.T) {
    24  	eg := EgressRule{}
    25  	eg.ToGroups = []Groups{
    26  		GetGroupsRule(),
    27  	}
    28  	require.Equal(t, true, eg.RequiresDerivative())
    29  }
    30  
    31  func TestCreateDerivativeRuleWithoutToGroups(t *testing.T) {
    32  	eg := &EgressRule{
    33  		EgressCommonRule: EgressCommonRule{
    34  			ToEndpoints: []EndpointSelector{
    35  				{
    36  					LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{
    37  						"test": "true",
    38  					},
    39  					},
    40  				},
    41  			},
    42  		},
    43  	}
    44  	newRule, err := eg.CreateDerivative(context.TODO())
    45  	require.EqualValues(t, newRule, eg)
    46  	require.Nil(t, err)
    47  }
    48  
    49  func TestCreateDerivativeRuleWithToGroupsWitInvalidRegisterCallback(t *testing.T) {
    50  	cb := func(ctx context.Context, group *Groups) ([]netip.Addr, error) {
    51  		return []netip.Addr{}, fmt.Errorf("Invalid error")
    52  	}
    53  	RegisterToGroupsProvider(AWSProvider, cb)
    54  
    55  	eg := &EgressRule{
    56  		EgressCommonRule: EgressCommonRule{
    57  			ToGroups: []Groups{
    58  				GetGroupsRule(),
    59  			},
    60  		},
    61  	}
    62  	_, err := eg.CreateDerivative(context.TODO())
    63  	require.Error(t, err)
    64  }
    65  
    66  func TestCreateDerivativeRuleWithToGroupsAndToPorts(t *testing.T) {
    67  	cb := GetCallBackWithRule("192.168.1.1")
    68  	RegisterToGroupsProvider(AWSProvider, cb)
    69  
    70  	eg := &EgressRule{
    71  		EgressCommonRule: EgressCommonRule{
    72  			ToGroups: []Groups{
    73  				GetGroupsRule(),
    74  			},
    75  		},
    76  	}
    77  
    78  	// Checking that the derivative rule is working correctly
    79  	require.Equal(t, true, eg.RequiresDerivative())
    80  
    81  	newRule, err := eg.CreateDerivative(context.TODO())
    82  	require.Nil(t, err)
    83  	require.Equal(t, 0, len(newRule.ToGroups))
    84  	require.Equal(t, 1, len(newRule.ToCIDRSet))
    85  }
    86  
    87  func TestCreateDerivativeWithoutErrorAndNoIPs(t *testing.T) {
    88  	// Testing that if the len of the Ips returned by provider is 0 to block
    89  	// all the IPS outside.
    90  	cb := GetCallBackWithRule()
    91  	RegisterToGroupsProvider(AWSProvider, cb)
    92  
    93  	eg := &EgressRule{
    94  		EgressCommonRule: EgressCommonRule{
    95  			ToGroups: []Groups{
    96  				GetGroupsRule(),
    97  			},
    98  		},
    99  	}
   100  
   101  	// Checking that the derivative rule is working correctly
   102  	require.Equal(t, true, eg.RequiresDerivative())
   103  
   104  	newRule, err := eg.CreateDerivative(context.TODO())
   105  	require.Nil(t, err)
   106  	require.EqualValues(t, &EgressRule{}, newRule)
   107  }
   108  
   109  func TestIsLabelBasedEgress(t *testing.T) {
   110  	setUpSuite(t)
   111  
   112  	type args struct {
   113  		eg *EgressRule
   114  	}
   115  	type wanted struct {
   116  		isLabelBased bool
   117  	}
   118  
   119  	tests := []struct {
   120  		name        string
   121  		setupArgs   func() args
   122  		setupWanted func() wanted
   123  	}{
   124  		{
   125  			name: "label-based-rule",
   126  			setupArgs: func() args {
   127  				return args{
   128  					eg: &EgressRule{
   129  						EgressCommonRule: EgressCommonRule{
   130  							ToEndpoints: []EndpointSelector{
   131  								{
   132  									LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{
   133  										"test": "true",
   134  									},
   135  									},
   136  								},
   137  							},
   138  						},
   139  					},
   140  				}
   141  			},
   142  			setupWanted: func() wanted {
   143  				return wanted{
   144  					isLabelBased: true,
   145  				}
   146  			},
   147  		},
   148  		{
   149  			name: "cidr-based-rule",
   150  			setupArgs: func() args {
   151  				return args{
   152  					&EgressRule{
   153  						EgressCommonRule: EgressCommonRule{
   154  							ToCIDR: CIDRSlice{"192.0.0.0/3"},
   155  						},
   156  					},
   157  				}
   158  			},
   159  			setupWanted: func() wanted {
   160  				return wanted{
   161  					isLabelBased: true,
   162  				}
   163  			},
   164  		},
   165  		{
   166  			name: "cidrset-based-rule",
   167  			setupArgs: func() args {
   168  				return args{
   169  					&EgressRule{
   170  						EgressCommonRule: EgressCommonRule{
   171  							ToCIDRSet: CIDRRuleSlice{
   172  								{
   173  									Cidr: "192.0.0.0/3",
   174  								},
   175  							},
   176  						},
   177  					},
   178  				}
   179  			},
   180  			setupWanted: func() wanted {
   181  				return wanted{
   182  					isLabelBased: true,
   183  				}
   184  			},
   185  		},
   186  		{
   187  			name: "rule-with-requirements",
   188  			setupArgs: func() args {
   189  				return args{
   190  					&EgressRule{
   191  						EgressCommonRule: EgressCommonRule{
   192  							ToRequires: []EndpointSelector{
   193  								{
   194  									LabelSelector: &slim_metav1.LabelSelector{MatchLabels: map[string]string{
   195  										"test": "true",
   196  									},
   197  									},
   198  								},
   199  							},
   200  						},
   201  					},
   202  				}
   203  			},
   204  			setupWanted: func() wanted {
   205  				return wanted{
   206  					isLabelBased: false,
   207  				}
   208  			},
   209  		},
   210  		{
   211  			name: "rule-with-services",
   212  			setupArgs: func() args {
   213  
   214  				svcLabels := map[string]string{
   215  					"app": "tested-service",
   216  				}
   217  				selector := ServiceSelector(NewESFromMatchRequirements(svcLabels, nil))
   218  				return args{
   219  					&EgressRule{
   220  						EgressCommonRule: EgressCommonRule{
   221  							ToServices: []Service{
   222  								{
   223  									K8sServiceSelector: &K8sServiceSelectorNamespace{
   224  										Selector:  selector,
   225  										Namespace: "",
   226  									},
   227  								},
   228  							},
   229  						},
   230  					},
   231  				}
   232  			},
   233  			setupWanted: func() wanted {
   234  				return wanted{
   235  					isLabelBased: false,
   236  				}
   237  			},
   238  		},
   239  		{
   240  			name: "rule-with-fqdn",
   241  			setupArgs: func() args {
   242  				return args{
   243  					&EgressRule{
   244  						ToFQDNs: FQDNSelectorSlice{
   245  							{
   246  								MatchName: "cilium.io",
   247  							},
   248  						},
   249  					},
   250  				}
   251  			},
   252  			setupWanted: func() wanted {
   253  				return wanted{
   254  					isLabelBased: false,
   255  				}
   256  			},
   257  		},
   258  		{
   259  			name: "rule-with-entities",
   260  			setupArgs: func() args {
   261  				return args{
   262  					&EgressRule{
   263  						EgressCommonRule: EgressCommonRule{
   264  							ToEntities: EntitySlice{
   265  								EntityHost,
   266  							},
   267  						},
   268  					},
   269  				}
   270  			},
   271  			setupWanted: func() wanted {
   272  				return wanted{
   273  					isLabelBased: true,
   274  				}
   275  			},
   276  		},
   277  		{
   278  			name: "rule-with-no-l3-specification",
   279  			setupArgs: func() args {
   280  				return args{
   281  					&EgressRule{
   282  						ToPorts: []PortRule{
   283  							{
   284  								Ports: []PortProtocol{
   285  									{
   286  										Port:     "80",
   287  										Protocol: ProtoTCP,
   288  									},
   289  								},
   290  							},
   291  						},
   292  					},
   293  				}
   294  			},
   295  			setupWanted: func() wanted {
   296  				return wanted{
   297  					isLabelBased: true,
   298  				}
   299  			},
   300  		},
   301  		{
   302  			name: "rule-with-icmp",
   303  			setupArgs: func() args {
   304  				icmpType := intstr.FromInt(8)
   305  				return args{
   306  					&EgressRule{
   307  						ICMPs: ICMPRules{
   308  							{
   309  								Fields: []ICMPField{
   310  									{
   311  										Type: &icmpType,
   312  									},
   313  								},
   314  							},
   315  						},
   316  					},
   317  				}
   318  			},
   319  			setupWanted: func() wanted {
   320  				return wanted{
   321  					isLabelBased: true,
   322  				}
   323  			},
   324  		},
   325  		{
   326  			name: "rule-with-icmp6",
   327  			setupArgs: func() args {
   328  				icmpType := intstr.FromInt(128)
   329  				return args{
   330  					&EgressRule{
   331  						ICMPs: ICMPRules{
   332  							{
   333  								Fields: []ICMPField{
   334  									{
   335  										Family: IPv6Family,
   336  										Type:   &icmpType,
   337  									},
   338  								},
   339  							},
   340  						},
   341  					},
   342  				}
   343  			},
   344  			setupWanted: func() wanted {
   345  				return wanted{
   346  					isLabelBased: true,
   347  				}
   348  			},
   349  		},
   350  	}
   351  
   352  	for _, tt := range tests {
   353  		args := tt.setupArgs()
   354  		want := tt.setupWanted()
   355  		require.Equal(t, nil, args.eg.sanitize(), fmt.Sprintf("Test name: %q", tt.name))
   356  		isLabelBased := args.eg.AllowsWildcarding()
   357  		require.EqualValues(t, want.isLabelBased, isLabelBased, fmt.Sprintf("Test name: %q", tt.name))
   358  	}
   359  }
   360  
   361  func TestEgressCommonRuleDeepEqual(t *testing.T) {
   362  	testCases := []struct {
   363  		name      string
   364  		in, other *EgressCommonRule
   365  		expected  bool
   366  	}{
   367  		{
   368  			name:     "All fields are nil in both",
   369  			in:       &EgressCommonRule{},
   370  			other:    &EgressCommonRule{},
   371  			expected: true,
   372  		},
   373  		{
   374  			name: "All fields are empty in both",
   375  			in: &EgressCommonRule{
   376  				ToEndpoints: []EndpointSelector{},
   377  				ToCIDR:      []CIDR{},
   378  				ToCIDRSet:   []CIDRRule{},
   379  				ToEntities:  []Entity{},
   380  			},
   381  			other: &EgressCommonRule{
   382  				ToEndpoints: []EndpointSelector{},
   383  				ToCIDR:      []CIDR{},
   384  				ToCIDRSet:   []CIDRRule{},
   385  				ToEntities:  []Entity{},
   386  			},
   387  			expected: true,
   388  		},
   389  		{
   390  			name: "ToEndpoints is nil in left operand",
   391  			in: &EgressCommonRule{
   392  				ToEndpoints: nil,
   393  			},
   394  			other: &EgressCommonRule{
   395  				ToEndpoints: []EndpointSelector{},
   396  			},
   397  			expected: false,
   398  		},
   399  		{
   400  			name: "ToEndpoints is empty in left operand",
   401  			in: &EgressCommonRule{
   402  				ToEndpoints: []EndpointSelector{},
   403  			},
   404  			other: &EgressCommonRule{
   405  				ToEndpoints: nil,
   406  			},
   407  			expected: false,
   408  		},
   409  		{
   410  			name: "ToCIDR is nil in left operand",
   411  			in: &EgressCommonRule{
   412  				ToCIDR: nil,
   413  			},
   414  			other: &EgressCommonRule{
   415  				ToCIDR: []CIDR{},
   416  			},
   417  			expected: false,
   418  		},
   419  		{
   420  			name: "ToCIDR is empty in left operand",
   421  			in: &EgressCommonRule{
   422  				ToCIDR: []CIDR{},
   423  			},
   424  			other: &EgressCommonRule{
   425  				ToCIDR: nil,
   426  			},
   427  			expected: false,
   428  		},
   429  		{
   430  			name: "ToCIDRSet is nil in left operand",
   431  			in: &EgressCommonRule{
   432  				ToCIDRSet: nil,
   433  			},
   434  			other: &EgressCommonRule{
   435  				ToCIDRSet: []CIDRRule{},
   436  			},
   437  			expected: false,
   438  		},
   439  		{
   440  			name: "ToCIDRSet is empty in left operand",
   441  			in: &EgressCommonRule{
   442  				ToCIDRSet: []CIDRRule{},
   443  			},
   444  			other: &EgressCommonRule{
   445  				ToCIDRSet: nil,
   446  			},
   447  			expected: false,
   448  		},
   449  		{
   450  			name: "ToEntities is nil in left operand",
   451  			in: &EgressCommonRule{
   452  				ToEntities: nil,
   453  			},
   454  			other: &EgressCommonRule{
   455  				ToEntities: []Entity{},
   456  			},
   457  			expected: false,
   458  		},
   459  		{
   460  			name: "ToEntities is empty in left operand",
   461  			in: &EgressCommonRule{
   462  				ToEntities: []Entity{},
   463  			},
   464  			other: &EgressCommonRule{
   465  				ToEntities: nil,
   466  			},
   467  			expected: false,
   468  		},
   469  	}
   470  	for _, tc := range testCases {
   471  		t.Run(tc.name, func(t *testing.T) {
   472  			require.Equal(t, tc.expected, tc.in.DeepEqual(tc.other))
   473  		})
   474  	}
   475  }