...

Source file src/github.com/linkerd/linkerd2/test/integration/deep/dualstack/dualstack_test.go

Documentation: github.com/linkerd/linkerd2/test/integration/deep/dualstack

     1  package dualstack
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/linkerd/linkerd2/testutil"
    13  )
    14  
    15  type IP struct {
    16  	IP string `json:"ip"`
    17  }
    18  
    19  var TestHelper *testutil.TestHelper
    20  
    21  func TestMain(m *testing.M) {
    22  	TestHelper = testutil.NewTestHelper()
    23  	// Block test execution until control plane is running
    24  	TestHelper.WaitUntilDeployReady(testutil.LinkerdDeployReplicasEdge)
    25  	os.Exit(m.Run())
    26  }
    27  
    28  // TestDualStack creates an injected pod that starts two servers, one listening
    29  // on the IPv4 wildcard address and serving the string "IPv4", and another
    30  // listening on the IPv6 wildcard address and serving the string "IPv6". They
    31  // are fronted by a DualStack Service. We test that we can reach those two IPs
    32  // directly, and that making a request to the service's FQDN always hits the
    33  // IPv6 endpoint.
    34  func TestDualStack(t *testing.T) {
    35  	if !TestHelper.DualStack() {
    36  		t.Skip("Skipping Skip DualStack test")
    37  	}
    38  
    39  	TestHelper.WithDataPlaneNamespace(context.Background(), "dualstack-test", map[string]string{}, t, func(t *testing.T, ns string) {
    40  		out, err := TestHelper.Kubectl("",
    41  			"create", "configmap", "go-app",
    42  			"--from-file=main.go=testdata/ipfamilies-server.go",
    43  			"-n", ns,
    44  		)
    45  		if err != nil {
    46  			testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
    47  		}
    48  
    49  		out, err = TestHelper.Kubectl("",
    50  			"apply", "-f", "testdata/ipfamilies-server-client.yml",
    51  			"-n", ns,
    52  		)
    53  		if err != nil {
    54  			testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
    55  		}
    56  
    57  		checkPods(t, ns, "ipfamilies-server")
    58  		checkPods(t, ns, "client")
    59  
    60  		var clientIPv6, serverIPv4, serverIPv6 string
    61  
    62  		t.Run("Retrieve pod IPs", func(t *testing.T) {
    63  			cmd := []string{
    64  				"get", "po",
    65  				"-o", "jsonpath='{.items[*].status.podIPs}'",
    66  				"-n", ns,
    67  			}
    68  
    69  			out, err = TestHelper.Kubectl("", append(cmd, "-l", "app=server")...)
    70  			if err != nil {
    71  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
    72  			}
    73  
    74  			var IPs []IP
    75  			out = strings.Trim(out, "'")
    76  			if err = json.Unmarshal([]byte(out), &IPs); err != nil {
    77  				testutil.AnnotatedFatalf(t, "error unmarshaling JSON", "error unmarshaling JSON '%s': %s", out, err)
    78  			}
    79  			if len(IPs) != 2 {
    80  				testutil.AnnotatedFatalf(t, "unexpected number of IPs", "expected 2 IPs, got %s", fmt.Sprint(len(IPs)))
    81  			}
    82  			serverIPv4 = IPs[0].IP
    83  			serverIPv6 = IPs[1].IP
    84  
    85  			out, err = TestHelper.Kubectl("", append(cmd, "-l", "app=client")...)
    86  			if err != nil {
    87  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
    88  			}
    89  
    90  			out = strings.Trim(out, "'")
    91  			if err = json.Unmarshal([]byte(out), &IPs); err != nil {
    92  				testutil.AnnotatedFatalf(t, "error unmarshaling JSON", "error unmarshaling JSON '%s': %s", out, err)
    93  			}
    94  			if len(IPs) != 2 {
    95  				testutil.AnnotatedFatalf(t, "unexpected number of IPs", "expected 2 IPs, got %s", fmt.Sprint(len(IPs)))
    96  			}
    97  			clientIPv6 = IPs[1].IP
    98  		})
    99  
   100  		t.Run("Apply policy", func(t *testing.T) {
   101  			file, err := os.Open("testdata/ipfamilies-policy.yml")
   102  			if err != nil {
   103  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v", err)
   104  			}
   105  			defer file.Close()
   106  			manifest, err := io.ReadAll(file)
   107  			if err != nil {
   108  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v", err)
   109  			}
   110  			in := strings.ReplaceAll(string(manifest), "{IPv6}", clientIPv6)
   111  			out, err = TestHelper.KubectlApply(in, ns)
   112  			if err != nil {
   113  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
   114  			}
   115  		})
   116  
   117  		t.Run("Hit IPv4 addr directly", func(t *testing.T) {
   118  			out, err = TestHelper.Kubectl("",
   119  				"exec", "deploy/client",
   120  				"-c", "curl",
   121  				"-n", ns,
   122  				"--",
   123  				"curl", "-s", "http://"+serverIPv4+":8080",
   124  			)
   125  			if err != nil {
   126  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
   127  			}
   128  			if out != "IPv4\n" {
   129  				testutil.AnnotatedFatalf(t, "unexpected output", "expected 'IPv4', received '%s'", out)
   130  			}
   131  		})
   132  
   133  		t.Run("Hit IPv6 addr directly", func(t *testing.T) {
   134  			out, err = TestHelper.Kubectl("",
   135  				"exec", "deploy/client",
   136  				"-c", "curl",
   137  				"-n", ns,
   138  				"--",
   139  				"curl", "-s", "http://["+serverIPv6+"]:8080",
   140  			)
   141  			if err != nil {
   142  				testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
   143  			}
   144  			if out != "IPv6\n" {
   145  				testutil.AnnotatedFatalf(t, "expected 'IPv6', received '%s'", out)
   146  			}
   147  		})
   148  
   149  		t.Run("Hit FQDN directly (should always resolve to IPv6)", func(t *testing.T) {
   150  			for i := 0; i < 10; i++ {
   151  				out, err = TestHelper.Kubectl("",
   152  					"exec", "deploy/client",
   153  					"-c", "curl",
   154  					"-n", ns,
   155  					"--",
   156  					"curl", "-s", "http://ipfamilies-server:8080",
   157  				)
   158  				if err != nil {
   159  					testutil.AnnotatedFatalf(t, "unexpected error", "unexpected error: %v\noutput:\n%s", err, out)
   160  				}
   161  				if out != "IPv6\n" {
   162  					testutil.AnnotatedFatalf(t, "expected 'IPv6', received '%s'", out)
   163  				}
   164  			}
   165  		})
   166  	})
   167  }
   168  
   169  func checkPods(t *testing.T, ns, pod string) {
   170  	t.Helper()
   171  
   172  	if err := TestHelper.CheckPods(context.Background(), ns, pod, 1); err != nil {
   173  		//nolint:errorlint
   174  		if rce, ok := err.(*testutil.RestartCountError); ok {
   175  			testutil.AnnotatedWarn(t, "CheckPods timed-out", rce)
   176  		} else {
   177  			testutil.AnnotatedError(t, "CheckPods timed-out", err)
   178  		}
   179  	}
   180  }
   181  

View as plain text