github.com/cilium/cilium@v1.16.2/pkg/endpointmanager/endpointsynchronizer_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package endpointmanager
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"testing"
    10  
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/stretchr/testify/assert"
    13  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/apimachinery/pkg/types"
    15  
    16  	"github.com/cilium/cilium/pkg/endpoint"
    17  	v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    18  	slim_corev1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/api/core/v1"
    19  	"github.com/cilium/cilium/pkg/node"
    20  )
    21  
    22  func Test_updateCEPUID(t *testing.T) {
    23  	podWithHostIP := func(hostIP string) *slim_corev1.Pod {
    24  		return &slim_corev1.Pod{
    25  			Status: slim_corev1.PodStatus{
    26  				HostIP: hostIP,
    27  			},
    28  		}
    29  	}
    30  	epWithUID := func(uid string, pod *slim_corev1.Pod) *endpoint.Endpoint {
    31  		ep := &endpoint.Endpoint{}
    32  		ep.SetPod(pod)
    33  		ep.SetCiliumEndpointUID(types.UID(uid))
    34  		return ep
    35  	}
    36  	testIP := "1.2.3.4"
    37  	someUID := func(s string) *types.UID {
    38  		id := types.UID(s)
    39  		return &id
    40  	}
    41  	for name, test := range map[string]struct {
    42  		err           error
    43  		cep           *v2.CiliumEndpoint
    44  		ep            *endpoint.Endpoint
    45  		nodeIP        string
    46  		expectedEPUID *types.UID
    47  	}{
    48  		// In this test, our CEP has a UID that is different from the local Endpoint.
    49  		// This means that the CEP is not owned by this EP.
    50  		// Ownership should fail due to Endpoint not having a pod.
    51  		// This condition is typically triggered when the pod is deleted.
    52  		"no pod": {
    53  			ep:     epWithUID("000", nil),
    54  			err:    fmt.Errorf("no pod"),
    55  			nodeIP: testIP,
    56  			cep: &v2.CiliumEndpoint{
    57  				ObjectMeta: v1.ObjectMeta{
    58  					UID: "111", // Different UID from the local Endpoint.
    59  				},
    60  			},
    61  		},
    62  		"CiliumEndpoint not local": {
    63  			// The CEP is explicitly not local (i.e the CEP's pod's hostIP doesn't match the nodeIP).
    64  			ep:     epWithUID("1234", podWithHostIP(testIP)),
    65  			nodeIP: "4.3.2.1",
    66  			err:    fmt.Errorf("is not local"),
    67  			cep: &v2.CiliumEndpoint{
    68  				ObjectMeta: v1.ObjectMeta{UID: "1111"},
    69  			},
    70  		},
    71  		"CiliumEndpoint not local, but already owned": {
    72  			// The CEP is explicitly not local. But the CEP is already owned by the endpoint.
    73  			// So ownership should proceed without error.
    74  			ep:     epWithUID("000", podWithHostIP("4.3.2.1")), // matches CEP.
    75  			nodeIP: testIP,
    76  			cep: &v2.CiliumEndpoint{
    77  				ObjectMeta: v1.ObjectMeta{UID: "000"},
    78  			},
    79  		},
    80  		"ciliumendpoint already exists": {
    81  			// CEP already exists, on the same node, we cannot take ownership of it
    82  			// due to differing UID ref.
    83  			//
    84  			// This would be the case where two endpoint sync controllers are running for
    85  			// a Pod with the same namespace/name on the same Agent, so we'd have to wait
    86  			// until the other controller terminates and cleans up the CEP.
    87  			err:           fmt.Errorf("did not match CEP UID"),
    88  			expectedEPUID: someUID("b"),
    89  			ep:            epWithUID("b", podWithHostIP(testIP)),
    90  			nodeIP:        testIP,
    91  			cep: &v2.CiliumEndpoint{
    92  				ObjectMeta: v1.ObjectMeta{UID: types.UID("a")},
    93  			},
    94  		},
    95  		// This is the normal case of taking ownership.
    96  		// Note that this also happens when the nodeIP changes during a reboot
    97  		// but the endpoint snapshot is lost on reboot. The endpoint UID will
    98  		// remain empty, but the CEP object will have a UID and a wrong nodeIP.
    99  		// It is to counter this case that we check the pods hostIP against the
   100  		// nodeIP instaed of the CEP's node IP.
   101  		"take ownership of cep due to empty CiliumEndpointUID ref": {
   102  			ep:            epWithUID("", podWithHostIP(testIP)),
   103  			nodeIP:        testIP,
   104  			expectedEPUID: someUID("a"),
   105  			cep: &v2.CiliumEndpoint{
   106  				ObjectMeta: v1.ObjectMeta{UID: types.UID("a")},
   107  				Status: v2.EndpointStatus{
   108  					Networking: &v2.EndpointNetworking{
   109  						NodeIP: "4.5.6.7",
   110  					},
   111  				},
   112  			},
   113  		},
   114  	} {
   115  		t.Run(name, func(t *testing.T) {
   116  			assert := assert.New(t)
   117  			var err error
   118  			node.WithTestLocalNodeStore(func() {
   119  				node.UpdateLocalNodeInTest(func(n *node.LocalNode) {
   120  					n.SetNodeInternalIP(net.ParseIP(test.nodeIP))
   121  				})
   122  				err = updateCEPUID(logrus.StandardLogger().WithFields(logrus.Fields{}), test.ep, test.cep)
   123  			})
   124  			if test.err == nil {
   125  				assert.NoError(err)
   126  			} else {
   127  				assert.ErrorContains(err, test.err.Error())
   128  			}
   129  			if test.expectedEPUID != nil {
   130  				assert.Equal(*test.expectedEPUID, test.ep.GetCiliumEndpointUID())
   131  			}
   132  		})
   133  
   134  	}
   135  }