Repository: srl-labs/containerlab
Pull request #1672 (2023-10-24 21:49:56)

Dns fetch with slices instead of map for predictability of the order


Patch:
diff --git a/docs/rn/0.47.md b/docs/rn/0.47.md
index b253122c..f98a7c32 100644
--- a/docs/rn/0.47.md
+++ b/docs/rn/0.47.md
@@ -39,4 +39,4 @@ Containerlab now [generates an SSH config](../manual/inventory.md#ssh-config) fi
 
 ### 0.47.1
 
-* Do not extract more than 3 DNS servers from the host's resolv.conf #1671
+* Do not extract more than 3 DNS servers from the host's resolv.conf #1671, #1672
diff --git a/utils/resolve.go b/utils/resolve.go
index 68515b61..f25e632b 100644
--- a/utils/resolve.go
+++ b/utils/resolve.go
@@ -7,13 +7,17 @@ import (
 	"strings"
 
 	log "github.com/sirupsen/logrus"
+	"golang.org/x/exp/slices"
 )
 
 // ExtractDNSServersFromResolvConf extracts IP addresses
 // of the DNS servers from the resolv.conf-formatted files passed in filenames list.
 // Returns a list of IP addresses of the DNS servers.
 func ExtractDNSServersFromResolvConf(filesys fs.FS, filenames []string) ([]string, error) {
-	DNSServersMap := map[string]struct{}{}
+	// list of DNS servers up to 10 elements
+	// since realistically there should be no more than 3
+	// DNS servers, we leave some room for duplicates
+	DNSServers := make([]string, 0, 10)
 
 	for _, filename := range filenames {
 		readFile, err := filesys.Open(filename)
@@ -39,27 +43,23 @@ func ExtractDNSServersFromResolvConf(filesys fs.FS, filenames []string) ([]strin
 					continue
 				}
 
-				DNSServersMap[ip.String()] = struct{}{}
+				DNSServers = append(DNSServers, ip.String())
 			}
 		}
 
 		readFile.Close()
 	}
 
-	if len(DNSServersMap) == 0 {
+	if len(DNSServers) == 0 {
 		return nil, nil
 	}
 
-	DNSServers := make([]string, 0, len(DNSServersMap))
-	var count int
-	for k := range DNSServersMap {
-		if count == 3 {
-			// keep only the first three DNS servers
-			// since C DNS resolver can't handle more
-			break
-		}
-		DNSServers = append(DNSServers, k)
-		count++
+	// remove duplicates
+	slices.Sort(DNSServers)
+	DNSServers = slices.Compact(DNSServers)
+
+	if len(DNSServers) > 3 {
+		DNSServers = DNSServers[:3]
 	}
 
 	return DNSServers, nil


Test patch:
diff --git a/utils/resolve_test.go b/utils/resolve_test.go
index d641fd40..0625ab9f 100644
--- a/utils/resolve_test.go
+++ b/utils/resolve_test.go
@@ -2,12 +2,10 @@ package utils
 
 import (
 	"io/fs"
-	"strings"
 	"testing"
 	"testing/fstest"
 
 	"github.com/google/go-cmp/cmp"
-	"github.com/google/go-cmp/cmp/cmpopts"
 )
 
 func TestExtractDNSServersFromResolvConf(t *testing.T) {
@@ -132,6 +130,7 @@ search .
 					"etc/someother/resolv.conf": &fstest.MapFile{
 						Data: []byte(
 							`
+nameserver 2.2.2.2
 nameserver 8.8.8.8
 options edns0 trust-ad
 search .					
@@ -141,7 +140,7 @@ search .
 				},
 				filenames: []string{"etc/resolv.conf", "etc/someother/resolv.conf"},
 			},
-			want:    []string{"1.1.1.1", "8.8.8.8"},
+			want:    []string{"1.1.1.1", "2.2.2.2", "8.8.8.8"},
 			wantErr: false,
 		},
 		{
@@ -163,16 +162,7 @@ search .
 				return
 			}
 
-			if diff := cmp.Diff(got, tt.want, cmpopts.SortSlices(func(s1, s2 string) bool {
-				switch strings.Compare(s1, s2) {
-				case -1:
-					return false
-				case 0:
-					return true
-				}
-				return true
-			},
-			)); diff != "" {
+			if diff := cmp.Diff(got, tt.want); diff != "" {
 				t.Errorf(diff)
 			}
 		})