github.com/cilium/cilium@v1.16.2/pkg/fqdn/name_manager_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package fqdn 5 6 import ( 7 "context" 8 "net" 9 "net/netip" 10 "regexp" 11 "testing" 12 13 "github.com/stretchr/testify/require" 14 15 "github.com/cilium/cilium/pkg/fqdn/dns" 16 "github.com/cilium/cilium/pkg/ipcache" 17 ipcacheTypes "github.com/cilium/cilium/pkg/ipcache/types" 18 "github.com/cilium/cilium/pkg/labels" 19 "github.com/cilium/cilium/pkg/policy/api" 20 "github.com/cilium/cilium/pkg/time" 21 ) 22 23 type mockIPCache struct { 24 metadata map[netip.Prefix]map[ipcacheTypes.ResourceID]labels.Labels 25 } 26 27 func newMockIPCache() *mockIPCache { 28 return &mockIPCache{ 29 metadata: make(map[netip.Prefix]map[ipcacheTypes.ResourceID]labels.Labels), 30 } 31 } 32 33 func (m *mockIPCache) labelsForPrefix(prefix netip.Prefix) labels.Labels { 34 lbls := labels.Labels{} 35 for _, l := range m.metadata[prefix] { 36 lbls.MergeLabels(l) 37 } 38 return lbls 39 } 40 41 func (m *mockIPCache) UpsertMetadataBatch(updates ...ipcache.MU) (revision uint64) { 42 for _, mu := range updates { 43 prefixMetadata, ok := m.metadata[mu.Prefix] 44 if !ok { 45 prefixMetadata = make(map[ipcacheTypes.ResourceID]labels.Labels) 46 } 47 48 for _, aux := range mu.Metadata { 49 if lbls, ok := aux.(labels.Labels); ok { 50 prefixMetadata[mu.Resource] = lbls 51 break 52 } 53 } 54 55 m.metadata[mu.Prefix] = prefixMetadata 56 } 57 58 return 0 59 } 60 61 func (m *mockIPCache) RemoveMetadataBatch(updates ...ipcache.MU) (revision uint64) { 62 for _, mu := range updates { 63 for _, aux := range mu.Metadata { 64 if _, ok := aux.(labels.Labels); ok { 65 delete(m.metadata[mu.Prefix], mu.Resource) 66 break 67 } 68 } 69 70 if len(m.metadata[mu.Prefix]) == 0 { 71 delete(m.metadata, mu.Prefix) 72 } 73 } 74 75 return 0 76 } 77 78 func (m *mockIPCache) WaitForRevision(ctx context.Context, rev uint64) error { 79 return nil 80 } 81 82 func ipsFromPrefixes(t *testing.T, prefixes ...netip.Prefix) (ips []net.IP) { 83 t.Helper() 84 85 for _, p := range prefixes { 86 if !p.IsSingleIP() { 87 t.Fatalf("invalid prefix: %s", p) 88 } 89 90 ips = append(ips, p.Addr().AsSlice()) 91 } 92 93 return ips 94 } 95 96 func TestNameManagerIPCacheUpdates(t *testing.T) { 97 ipc := newMockIPCache() 98 nameManager := NewNameManager(Config{ 99 MinTTL: 1, 100 Cache: NewDNSCache(0), 101 IPCache: ipc, 102 }) 103 104 nameManager.RegisterFQDNSelector(ciliumIOSel) 105 106 // Simulate lookup for single selector 107 prefix := netip.MustParsePrefix("1.1.1.1/32") 108 nameManager.UpdateGenerateDNS(context.TODO(), time.Now(), map[string]*DNSIPRecords{dns.FQDN("cilium.io"): {TTL: 60, IPs: ipsFromPrefixes(t, prefix)}}) 109 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{ciliumIOSel.IdentityLabel()})) 110 111 // Add match pattern 112 nameManager.RegisterFQDNSelector(ciliumIOSelMatchPattern) 113 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{ciliumIOSel.IdentityLabel(), ciliumIOSelMatchPattern.IdentityLabel()})) 114 115 // Remove cilium.io matchname, add github.com match name 116 nameManager.RegisterFQDNSelector(githubSel) 117 nameManager.UnregisterFQDNSelector(ciliumIOSel) 118 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{ciliumIOSelMatchPattern.IdentityLabel()})) 119 120 // Same IP matched by two selectors 121 nameManager.UpdateGenerateDNS(context.TODO(), time.Now(), map[string]*DNSIPRecords{dns.FQDN("github.com"): {TTL: 60, IPs: ipsFromPrefixes(t, prefix)}}) 122 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{ciliumIOSelMatchPattern.IdentityLabel(), githubSel.IdentityLabel()})) 123 124 // Additional unique IPs for each selector 125 githubPrefix := netip.MustParsePrefix("10.0.0.2/32") 126 awesomePrefix := netip.MustParsePrefix("10.0.0.3/32") 127 nameManager.UpdateGenerateDNS(context.TODO(), time.Now(), map[string]*DNSIPRecords{ 128 dns.FQDN("github.com"): {TTL: 60, IPs: ipsFromPrefixes(t, githubPrefix)}, 129 dns.FQDN("awesomecilium.io"): {TTL: 60, IPs: ipsFromPrefixes(t, awesomePrefix)}, 130 }) 131 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{ciliumIOSelMatchPattern.IdentityLabel(), githubSel.IdentityLabel()})) 132 require.Equal(t, ipc.labelsForPrefix(githubPrefix), labels.FromSlice([]labels.Label{githubSel.IdentityLabel()})) 133 require.Equal(t, ipc.labelsForPrefix(awesomePrefix), labels.FromSlice([]labels.Label{ciliumIOSelMatchPattern.IdentityLabel()})) 134 135 // Removing selector should remove from IPCache 136 nameManager.UnregisterFQDNSelector(ciliumIOSelMatchPattern) 137 require.NotContains(t, ipc.metadata, awesomePrefix) 138 require.Equal(t, ipc.labelsForPrefix(prefix), labels.FromSlice([]labels.Label{githubSel.IdentityLabel()})) 139 require.Equal(t, ipc.labelsForPrefix(githubPrefix), labels.FromSlice([]labels.Label{githubSel.IdentityLabel()})) 140 } 141 142 func Test_deriveLabelsForNames(t *testing.T) { 143 ciliumIORe, err := ciliumIOSel.ToRegex() 144 require.NoError(t, err) 145 githubRe, err := githubSel.ToRegex() 146 require.NoError(t, err) 147 ciliumIOSelMatchPatternRe, err := ciliumIOSelMatchPattern.ToRegex() 148 require.NoError(t, err) 149 150 selectors := map[api.FQDNSelector]*regexp.Regexp{ 151 ciliumIOSel: ciliumIORe, 152 githubSel: githubRe, 153 ciliumIOSelMatchPattern: ciliumIOSelMatchPatternRe, 154 } 155 156 nomatchIP := netip.MustParseAddr("10.10.0.1") 157 githubIP := netip.MustParseAddr("10.20.0.1") 158 ciliumIP1 := netip.MustParseAddr("10.30.0.1") 159 ciliumIP2 := netip.MustParseAddr("10.30.0.2") 160 161 names := map[string][]netip.Addr{ 162 "nomatch.local.": {nomatchIP}, 163 "github.com.": {githubIP}, 164 "cilium.io.": {ciliumIP1}, 165 "awesomecilium.io.": {ciliumIP1, ciliumIP2}, 166 } 167 168 require.Equal(t, deriveLabelsForNames(names, selectors), map[string]nameMetadata{ 169 "nomatch.local.": { 170 addrs: []netip.Addr{nomatchIP}, 171 labels: labels.Labels{}, 172 }, 173 "github.com.": { 174 addrs: []netip.Addr{githubIP}, 175 labels: labels.NewLabelsFromSortedList("fqdn:github.com"), 176 }, 177 "cilium.io.": { 178 addrs: []netip.Addr{ciliumIP1}, 179 labels: labels.NewLabelsFromSortedList("fqdn:*cilium.io.;fqdn:cilium.io"), 180 }, 181 "awesomecilium.io.": { 182 addrs: []netip.Addr{ciliumIP1, ciliumIP2}, 183 labels: labels.NewLabelsFromSortedList("fqdn:*cilium.io."), 184 }, 185 }) 186 }