github.com/cilium/cilium@v1.16.2/pkg/node/types/node_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package types
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  
    15  	"github.com/cilium/cilium/pkg/annotation"
    16  	"github.com/cilium/cilium/pkg/cidr"
    17  	ipamTypes "github.com/cilium/cilium/pkg/ipam/types"
    18  	ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    19  	"github.com/cilium/cilium/pkg/node/addressing"
    20  	"github.com/cilium/cilium/pkg/source"
    21  )
    22  
    23  func TestGetNodeIP(t *testing.T) {
    24  	n := Node{
    25  		Name: "node-1",
    26  		IPAddresses: []Address{
    27  			{IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP},
    28  		},
    29  	}
    30  	ip := n.GetNodeIP(false)
    31  	// Return the only IP present
    32  	require.Equal(t, ip, net.ParseIP("192.0.2.3"))
    33  
    34  	n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP})
    35  	ip = n.GetNodeIP(false)
    36  	// The next priority should be NodeExternalIP
    37  	require.Equal(t, ip, net.ParseIP("192.0.2.3"))
    38  
    39  	n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("198.51.100.2"), Type: addressing.NodeInternalIP})
    40  	ip = n.GetNodeIP(false)
    41  	// The next priority should be NodeInternalIP
    42  	require.Equal(t, ip, net.ParseIP("198.51.100.2"))
    43  
    44  	n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("2001:DB8::1"), Type: addressing.NodeExternalIP})
    45  	ip = n.GetNodeIP(true)
    46  	// The next priority should be NodeExternalIP and IPv6
    47  	require.Equal(t, ip, net.ParseIP("2001:DB8::1"))
    48  
    49  	n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("2001:DB8::2"), Type: addressing.NodeInternalIP})
    50  	ip = n.GetNodeIP(true)
    51  	// The next priority should be NodeInternalIP and IPv6
    52  	require.Equal(t, ip, net.ParseIP("2001:DB8::2"))
    53  
    54  	n.IPAddresses = append(n.IPAddresses, Address{IP: net.ParseIP("198.51.100.2"), Type: addressing.NodeInternalIP})
    55  	ip = n.GetNodeIP(false)
    56  	// Should still return NodeInternalIP and IPv4
    57  	require.Equal(t, ip, net.ParseIP("198.51.100.2"))
    58  }
    59  
    60  func TestGetIPByType(t *testing.T) {
    61  	n := Node{
    62  		Name: "node-1",
    63  		IPAddresses: []Address{
    64  			{IP: net.ParseIP("192.0.2.3"), Type: addressing.NodeExternalIP},
    65  		},
    66  	}
    67  
    68  	ip := n.GetIPByType(addressing.NodeInternalIP, false)
    69  	require.Nil(t, ip)
    70  	ip = n.GetIPByType(addressing.NodeInternalIP, true)
    71  	require.Nil(t, ip)
    72  
    73  	ip = n.GetIPByType(addressing.NodeExternalIP, false)
    74  	require.Equal(t, ip, net.ParseIP("192.0.2.3"))
    75  	ip = n.GetIPByType(addressing.NodeExternalIP, true)
    76  	require.Nil(t, ip)
    77  
    78  	n = Node{
    79  		Name: "node-2",
    80  		IPAddresses: []Address{
    81  			{IP: net.ParseIP("f00b::1"), Type: addressing.NodeCiliumInternalIP},
    82  		},
    83  	}
    84  
    85  	ip = n.GetIPByType(addressing.NodeExternalIP, false)
    86  	require.Nil(t, ip)
    87  	ip = n.GetIPByType(addressing.NodeExternalIP, true)
    88  	require.Nil(t, ip)
    89  
    90  	ip = n.GetIPByType(addressing.NodeCiliumInternalIP, false)
    91  	require.Nil(t, ip)
    92  	ip = n.GetIPByType(addressing.NodeCiliumInternalIP, true)
    93  	require.Equal(t, ip, net.ParseIP("f00b::1"))
    94  
    95  	n = Node{
    96  		Name: "node-3",
    97  		IPAddresses: []Address{
    98  			{IP: net.ParseIP("192.42.0.3"), Type: addressing.NodeExternalIP},
    99  			{IP: net.ParseIP("f00d::1"), Type: addressing.NodeExternalIP},
   100  		},
   101  	}
   102  
   103  	ip = n.GetIPByType(addressing.NodeInternalIP, false)
   104  	require.Nil(t, ip)
   105  	ip = n.GetIPByType(addressing.NodeInternalIP, true)
   106  	require.Nil(t, ip)
   107  
   108  	ip = n.GetIPByType(addressing.NodeExternalIP, false)
   109  	require.Equal(t, ip, net.ParseIP("192.42.0.3"))
   110  	ip = n.GetIPByType(addressing.NodeExternalIP, true)
   111  	require.Equal(t, ip, net.ParseIP("f00d::1"))
   112  }
   113  
   114  func TestParseCiliumNode(t *testing.T) {
   115  	nodeResource := &ciliumv2.CiliumNode{
   116  		ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"},
   117  		Spec: ciliumv2.NodeSpec{
   118  			Addresses: []ciliumv2.NodeAddress{
   119  				{Type: addressing.NodeInternalIP, IP: "2.2.2.2"},
   120  				{Type: addressing.NodeExternalIP, IP: "3.3.3.3"},
   121  				{Type: addressing.NodeInternalIP, IP: "c0de::1"},
   122  				{Type: addressing.NodeExternalIP, IP: "c0de::2"},
   123  			},
   124  			Encryption: ciliumv2.EncryptionSpec{
   125  				Key: 10,
   126  			},
   127  			IPAM: ipamTypes.IPAMSpec{
   128  				PodCIDRs: []string{
   129  					"10.10.0.0/16",
   130  					"c0de::/96",
   131  					"10.20.0.0/16",
   132  					"c0fe::/96",
   133  				},
   134  			},
   135  			HealthAddressing: ciliumv2.HealthAddressingSpec{
   136  				IPv4: "1.1.1.1",
   137  				IPv6: "c0de::1",
   138  			},
   139  			IngressAddressing: ciliumv2.AddressPair{
   140  				IPV4: "1.1.1.2",
   141  				IPV6: "c0de::2",
   142  			},
   143  			NodeIdentity: uint64(12345),
   144  		},
   145  	}
   146  
   147  	n := ParseCiliumNode(nodeResource)
   148  	require.Equal(t, Node{
   149  		Name:   "foo",
   150  		Source: source.CustomResource,
   151  		IPAddresses: []Address{
   152  			{Type: addressing.NodeInternalIP, IP: net.ParseIP("2.2.2.2")},
   153  			{Type: addressing.NodeExternalIP, IP: net.ParseIP("3.3.3.3")},
   154  			{Type: addressing.NodeInternalIP, IP: net.ParseIP("c0de::1")},
   155  			{Type: addressing.NodeExternalIP, IP: net.ParseIP("c0de::2")},
   156  		},
   157  		EncryptionKey:           uint8(10),
   158  		IPv4AllocCIDR:           cidr.MustParseCIDR("10.10.0.0/16"),
   159  		IPv6AllocCIDR:           cidr.MustParseCIDR("c0de::/96"),
   160  		IPv4SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("10.20.0.0/16")},
   161  		IPv6SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("c0fe::/96")},
   162  		IPv4HealthIP:            net.ParseIP("1.1.1.1"),
   163  		IPv6HealthIP:            net.ParseIP("c0de::1"),
   164  		IPv4IngressIP:           net.ParseIP("1.1.1.2"),
   165  		IPv6IngressIP:           net.ParseIP("c0de::2"),
   166  		NodeIdentity:            uint32(12345),
   167  	}, n)
   168  }
   169  
   170  func TestNode_ToCiliumNode(t *testing.T) {
   171  	nodeResource := Node{
   172  		Name:   "foo",
   173  		Source: source.CustomResource,
   174  		IPAddresses: []Address{
   175  			{Type: addressing.NodeInternalIP, IP: net.ParseIP("2.2.2.2")},
   176  			{Type: addressing.NodeExternalIP, IP: net.ParseIP("3.3.3.3")},
   177  			{Type: addressing.NodeInternalIP, IP: net.ParseIP("c0de::1")},
   178  			{Type: addressing.NodeExternalIP, IP: net.ParseIP("c0de::2")},
   179  		},
   180  		EncryptionKey:           uint8(10),
   181  		IPv4AllocCIDR:           cidr.MustParseCIDR("10.10.0.0/16"),
   182  		IPv6AllocCIDR:           cidr.MustParseCIDR("c0de::/96"),
   183  		IPv4SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("10.20.0.0/16")},
   184  		IPv6SecondaryAllocCIDRs: []*cidr.CIDR{cidr.MustParseCIDR("c0fe::/96")},
   185  		IPv4HealthIP:            net.ParseIP("1.1.1.1"),
   186  		IPv6HealthIP:            net.ParseIP("c0de::1"),
   187  		IPv4IngressIP:           net.ParseIP("1.1.1.2"),
   188  		IPv6IngressIP:           net.ParseIP("c0de::2"),
   189  		NodeIdentity:            uint32(12345),
   190  		WireguardPubKey:         "6kiIGGPvMiadJ1brWTVfSGXheE3e3k5GjDTxfjMLYx8=",
   191  		Annotations: map[string]string{
   192  			annotation.BGPVRouterAnnoPrefix + "64512": "router-id=172.0.0.3",
   193  		},
   194  	}
   195  
   196  	n := nodeResource.ToCiliumNode()
   197  	require.Equal(t, &ciliumv2.CiliumNode{
   198  		ObjectMeta: metav1.ObjectMeta{
   199  			Name:      "foo",
   200  			Namespace: "",
   201  			Annotations: map[string]string{
   202  				annotation.BGPVRouterAnnoPrefix + "64512": "router-id=172.0.0.3",
   203  			},
   204  		},
   205  		Spec: ciliumv2.NodeSpec{
   206  			Addresses: []ciliumv2.NodeAddress{
   207  				{Type: addressing.NodeInternalIP, IP: "2.2.2.2"},
   208  				{Type: addressing.NodeExternalIP, IP: "3.3.3.3"},
   209  				{Type: addressing.NodeInternalIP, IP: "c0de::1"},
   210  				{Type: addressing.NodeExternalIP, IP: "c0de::2"},
   211  			},
   212  			Encryption: ciliumv2.EncryptionSpec{
   213  				Key: 10,
   214  			},
   215  			IPAM: ipamTypes.IPAMSpec{
   216  				PodCIDRs: []string{
   217  					"10.10.0.0/16",
   218  					"c0de::/96",
   219  					"10.20.0.0/16",
   220  					"c0fe::/96",
   221  				},
   222  			},
   223  			HealthAddressing: ciliumv2.HealthAddressingSpec{
   224  				IPv4: "1.1.1.1",
   225  				IPv6: "c0de::1",
   226  			},
   227  			IngressAddressing: ciliumv2.AddressPair{
   228  				IPV4: "1.1.1.2",
   229  				IPV6: "c0de::2",
   230  			},
   231  			NodeIdentity: uint64(12345),
   232  		},
   233  	}, n)
   234  }
   235  
   236  func TestNodeValidate(t *testing.T) {
   237  	tests := []struct {
   238  		name   string
   239  		node   Node
   240  		assert assert.ErrorAssertionFunc
   241  	}{
   242  		{
   243  			name:   "empty cluster",
   244  			node:   Node{Name: "bar"},
   245  			assert: assert.Error,
   246  		},
   247  		{
   248  			name:   "empty name",
   249  			node:   Node{Cluster: "foo"},
   250  			assert: assert.Error,
   251  		},
   252  		{
   253  			name:   "empty cluster ID",
   254  			node:   Node{Cluster: "foo", Name: "bar"},
   255  			assert: assert.NoError,
   256  		},
   257  		{
   258  			name:   "valid cluster ID",
   259  			node:   Node{Cluster: "foo", Name: "bar", ClusterID: 99},
   260  			assert: assert.NoError,
   261  		},
   262  		{
   263  			name:   "invalid cluster ID",
   264  			node:   Node{Cluster: "foo", Name: "bar", ClusterID: 260},
   265  			assert: assert.Error,
   266  		},
   267  	}
   268  
   269  	for _, tt := range tests {
   270  		t.Run(tt.name, func(t *testing.T) {
   271  			tt.assert(t, tt.node.validate())
   272  		})
   273  	}
   274  }
   275  
   276  func TestGetIPv4AllocCIDRs(t *testing.T) {
   277  	var (
   278  		cidr1 = cidr.MustParseCIDR("1.0.0.0/24")
   279  		cidr2 = cidr.MustParseCIDR("2.0.0.0/24")
   280  		cidr3 = cidr.MustParseCIDR("3.0.0.0/24")
   281  	)
   282  
   283  	var tests = []struct {
   284  		// name of test
   285  		name string
   286  		// primary ipv4 allocation cidr
   287  		allocCIDR *cidr.CIDR
   288  		// secondary ipv4 allocation cidrs
   289  		secAllocCIDRs []*cidr.CIDR
   290  		// expected ipv4 cidrs
   291  		expectedCIDRs []*cidr.CIDR
   292  	}{
   293  		{
   294  			name:          "nil cidrs",
   295  			allocCIDR:     nil,
   296  			secAllocCIDRs: nil,
   297  			expectedCIDRs: make([]*cidr.CIDR, 0),
   298  		},
   299  		{
   300  			name:          "one primary and no secondary cidrs",
   301  			allocCIDR:     cidr1,
   302  			secAllocCIDRs: nil,
   303  			expectedCIDRs: []*cidr.CIDR{cidr1},
   304  		},
   305  		{
   306  			name:          "one primary and one secondary cidr",
   307  			allocCIDR:     cidr1,
   308  			secAllocCIDRs: []*cidr.CIDR{cidr2},
   309  			expectedCIDRs: []*cidr.CIDR{cidr1, cidr2},
   310  		},
   311  		{
   312  			name:          "one primary and multiple secondary cidrs",
   313  			allocCIDR:     cidr1,
   314  			secAllocCIDRs: []*cidr.CIDR{cidr2, cidr3},
   315  			expectedCIDRs: []*cidr.CIDR{cidr1, cidr2, cidr3},
   316  		},
   317  	}
   318  	for _, tt := range tests {
   319  		t.Run(tt.name, func(t *testing.T) {
   320  			n := Node{
   321  				Name:                    fmt.Sprintf("node-%s", tt.name),
   322  				IPv4AllocCIDR:           tt.allocCIDR,
   323  				IPv4SecondaryAllocCIDRs: tt.secAllocCIDRs,
   324  			}
   325  
   326  			actual := n.GetIPv4AllocCIDRs()
   327  			assert.Equal(t, actual, tt.expectedCIDRs)
   328  		})
   329  	}
   330  }
   331  
   332  func TestGetIPv6AllocCIDRs(t *testing.T) {
   333  	var (
   334  		cidr2001 = cidr.MustParseCIDR("2001:db8::/32")
   335  		cidr2002 = cidr.MustParseCIDR("2002:db8::/32")
   336  		cidr2003 = cidr.MustParseCIDR("2003:db8::/32")
   337  	)
   338  
   339  	var tests = []struct {
   340  		// name of test
   341  		name string
   342  		// primary ipv6 allocation cidr
   343  		allocCIDR *cidr.CIDR
   344  		// secondary ipv6 allocation cidrs
   345  		secAllocCIDRs []*cidr.CIDR
   346  		// expected ipv6 cidrs
   347  		expectedCIDRs []*cidr.CIDR
   348  	}{
   349  		{
   350  			name:          "nil cidrs",
   351  			allocCIDR:     nil,
   352  			secAllocCIDRs: nil,
   353  			expectedCIDRs: make([]*cidr.CIDR, 0),
   354  		},
   355  		{
   356  			name:          "one primary and no secondary cidrs",
   357  			allocCIDR:     cidr2001,
   358  			secAllocCIDRs: nil,
   359  			expectedCIDRs: []*cidr.CIDR{cidr2001},
   360  		},
   361  		{
   362  			name:          "one primary and one secondary cidr",
   363  			allocCIDR:     cidr2001,
   364  			secAllocCIDRs: []*cidr.CIDR{cidr2002},
   365  			expectedCIDRs: []*cidr.CIDR{cidr2001, cidr2002},
   366  		},
   367  		{
   368  			name:          "one primary and multiple secondary cidrs",
   369  			allocCIDR:     cidr2001,
   370  			secAllocCIDRs: []*cidr.CIDR{cidr2002, cidr2003},
   371  			expectedCIDRs: []*cidr.CIDR{cidr2001, cidr2002, cidr2003},
   372  		},
   373  	}
   374  	for _, tt := range tests {
   375  		t.Run(tt.name, func(t *testing.T) {
   376  			n := Node{
   377  				Name:                    fmt.Sprintf("node-%s", tt.name),
   378  				IPv6AllocCIDR:           tt.allocCIDR,
   379  				IPv6SecondaryAllocCIDRs: tt.secAllocCIDRs,
   380  			}
   381  
   382  			actual := n.GetIPv6AllocCIDRs()
   383  			assert.Equal(t, actual, tt.expectedCIDRs)
   384  		})
   385  	}
   386  }