...

Source file src/edge-infra.dev/pkg/sds/remoteaccess/wireguard/integration/integration_test.go

Documentation: edge-infra.dev/pkg/sds/remoteaccess/wireguard/integration

     1  package integration
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	corev1 "k8s.io/api/core/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"sigs.k8s.io/controller-runtime/pkg/client"
    15  
    16  	"edge-infra.dev/pkg/sds/remoteaccess/constants"
    17  	"edge-infra.dev/pkg/sds/remoteaccess/wireguard"
    18  	"edge-infra.dev/test/f2"
    19  	"edge-infra.dev/test/f2/x/ktest"
    20  )
    21  
    22  var f f2.Framework
    23  
    24  var (
    25  	vpnNamespace = &corev1.Namespace{
    26  		ObjectMeta: metav1.ObjectMeta{
    27  			Name: constants.VPNNamespace,
    28  		},
    29  	}
    30  )
    31  
    32  func TestMain(m *testing.M) {
    33  	f = f2.New(context.Background(),
    34  		f2.WithExtensions(
    35  			ktest.New(),
    36  		)).
    37  		Setup(func(ctx f2.Context) (f2.Context, error) {
    38  			k, err := ktest.FromContext(ctx)
    39  			if err != nil {
    40  				return ctx, err
    41  			}
    42  			// Override timeouts if we aren't using a live cluster
    43  			if !*k.Env.UseExistingCluster {
    44  				k.Timeout = 5 * time.Second
    45  				k.Tick = 10 * time.Millisecond
    46  			}
    47  			return ctx, nil
    48  		}).Teardown()
    49  	os.Exit(f.Run(m))
    50  }
    51  
    52  func TestNew(t *testing.T) {
    53  	var (
    54  		k        *ktest.K8s
    55  		instance *wireguard.Instance
    56  		secret   *corev1.Secret
    57  		err      error
    58  	)
    59  	feature := f2.NewFeature("New").
    60  		Setup("create vpn namespace", func(ctx f2.Context, t *testing.T) f2.Context {
    61  			k = ktest.FromContextT(ctx, t)
    62  			require.NoError(t, k.Client.Create(ctx, vpnNamespace.DeepCopy()))
    63  			return ctx
    64  		}).
    65  		Test("new instance and K8s secret created without errors", func(ctx f2.Context, t *testing.T) f2.Context {
    66  			instance, err = wireguard.New(ctx, k.Client, "test", "1234-uuid-5678", nil)
    67  			assert.NoError(t, err)
    68  			return ctx
    69  		}).
    70  		Test("instance contains expected values", func(ctx f2.Context, t *testing.T) f2.Context {
    71  			assert.NotNil(t, instance.PublicKey)
    72  			assert.NotNil(t, instance.PrivateKey)
    73  			assert.Nil(t, instance.IPAddress)
    74  			return ctx
    75  		}).
    76  		Test("instance K8s secret exists", func(ctx f2.Context, t *testing.T) f2.Context {
    77  			secretKey := client.ObjectKey{Namespace: constants.VPNNamespace, Name: "keys-test-1234-uuid-5678"}
    78  			secret = &corev1.Secret{}
    79  			assert.NoError(t, k.Client.Get(ctx, secretKey, secret))
    80  			return ctx
    81  		}).
    82  		Test("instance K8s secret contains expected data", func(ctx f2.Context, t *testing.T) f2.Context {
    83  			assert.Equal(t, instance.GetPublicKey(), string(secret.Data[wireguard.SecretPublicKey]))
    84  			assert.Equal(t, instance.GetPrivateKey(), string(secret.Data[wireguard.SecretPrivateKey]))
    85  			assert.Equal(t, instance.GetIPAddress().String(), string(secret.Data[wireguard.SecretIPAddress]))
    86  			return ctx
    87  		}).
    88  		Teardown("delete instance K8s secret", func(ctx f2.Context, t *testing.T) f2.Context {
    89  			require.NoError(t, k.Client.Delete(ctx, secret))
    90  			return ctx
    91  		}).Feature()
    92  	f.Test(t, feature)
    93  }
    94  
    95  func TestUpdateIPAddress(t *testing.T) {
    96  	var (
    97  		k        *ktest.K8s
    98  		instance *wireguard.Instance
    99  		secret   *corev1.Secret
   100  		err      error
   101  	)
   102  	feature := f2.NewFeature("UpdateIPAddress").
   103  		Setup("create new instance", func(ctx f2.Context, t *testing.T) f2.Context {
   104  			k = ktest.FromContextT(ctx, t)
   105  			instance, err = wireguard.New(ctx, k.Client, "test", "1234-uuid-5678", nil)
   106  			require.NoError(t, err)
   107  			require.Nil(t, instance.IPAddress)
   108  			return ctx
   109  		}).
   110  		Test("successfully update IPAddress on instance", func(ctx f2.Context, t *testing.T) f2.Context {
   111  			newIP := net.ParseIP("1.2.3.4")
   112  			assert.NoError(t, instance.UpdateIPAddress(ctx, k.Client, "test", "1234-uuid-5678", newIP))
   113  			assert.Equal(t, newIP, instance.IPAddress)
   114  			return ctx
   115  		}).
   116  		Test("successfully update IPAddress on instance K8s secret", func(ctx f2.Context, t *testing.T) f2.Context {
   117  			secretKey := client.ObjectKey{Namespace: constants.VPNNamespace, Name: "keys-test-1234-uuid-5678"}
   118  			secret = &corev1.Secret{}
   119  			require.NoError(t, k.Client.Get(ctx, secretKey, secret))
   120  
   121  			assert.Equal(t, instance.GetPublicKey(), string(secret.Data[wireguard.SecretPublicKey]))
   122  			assert.Equal(t, instance.GetPrivateKey(), string(secret.Data[wireguard.SecretPrivateKey]))
   123  			assert.Equal(t, instance.GetIPAddress().String(), string(secret.Data[wireguard.SecretIPAddress]))
   124  			return ctx
   125  		}).
   126  		Teardown("delete instance K8s secret", func(ctx f2.Context, t *testing.T) f2.Context {
   127  			require.NoError(t, k.Client.Delete(ctx, secret))
   128  			return ctx
   129  		}).Feature()
   130  	f.Test(t, feature)
   131  }
   132  
   133  func TestGetInstance(t *testing.T) {
   134  	var (
   135  		k      *ktest.K8s
   136  		secret = &corev1.Secret{}
   137  	)
   138  	feature := f2.NewFeature("GetInstance").
   139  		Test("creates new instance with default secret expiry", func(ctx f2.Context, t *testing.T) f2.Context {
   140  			k = ktest.FromContextT(ctx, t)
   141  
   142  			instance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   143  			assert.NoError(t, err)
   144  			assert.NotNil(t, instance)
   145  			assert.NoError(t, k.Client.Get(ctx, client.ObjectKey{Name: "keys-wireguard-relay-cluster-infra", Namespace: constants.VPNNamespace}, secret))
   146  
   147  			expires, err := time.Parse(time.RFC3339, secret.Annotations[wireguard.SecretExpires])
   148  			assert.NoError(t, err)
   149  			assert.Equal(t, 30*24, int(time.Until(expires).Round(time.Hour).Abs().Hours()))
   150  			return ctx
   151  		}).
   152  		Test("creates new instance with configured secret expiry", func(ctx f2.Context, t *testing.T) f2.Context {
   153  			require.NoError(t, k.Client.Delete(ctx, secret))
   154  
   155  			os.Setenv(constants.SecretValidityEnvField, "2h")
   156  
   157  			instance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   158  			assert.NoError(t, err)
   159  			assert.NotNil(t, instance)
   160  			assert.NoError(t, k.Client.Get(ctx, client.ObjectKey{Name: "keys-wireguard-relay-cluster-infra", Namespace: constants.VPNNamespace}, secret))
   161  
   162  			expires, err := time.Parse(time.RFC3339, secret.Annotations[wireguard.SecretExpires])
   163  			assert.NoError(t, err)
   164  			assert.Equal(t, 2, int(time.Until(expires).Round(time.Hour).Abs().Hours()))
   165  			return ctx
   166  		}).
   167  		Test("recreate instance with previous IP when secret has expired", func(ctx f2.Context, t *testing.T) f2.Context {
   168  			oldInstance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   169  			require.NoError(t, err)
   170  			require.NoError(t, oldInstance.UpdateIPAddress(ctx, k.Client, constants.RelayName, "cluster-infra", net.ParseIP("1.2.3.4")))
   171  			require.NoError(t, k.Client.Get(ctx, client.ObjectKey{Name: "keys-wireguard-relay-cluster-infra", Namespace: constants.VPNNamespace}, secret))
   172  
   173  			oldExpiry := secret.Annotations[wireguard.SecretExpires]
   174  			oldPublicKey := string(secret.Data[wireguard.SecretPublicKey])
   175  			oldPrivateKey := string(secret.Data[wireguard.SecretPrivateKey])
   176  			oldIPAddress := string(secret.Data[wireguard.SecretIPAddress])
   177  
   178  			time.Sleep(time.Second)
   179  			secret.Annotations[wireguard.SecretExpires] = time.Now().Format(time.RFC3339)
   180  			require.NoError(t, k.Client.Update(ctx, secret))
   181  
   182  			instance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   183  			assert.NoError(t, err)
   184  			assert.NotNil(t, instance)
   185  			assert.NoError(t, k.Client.Get(ctx, client.ObjectKey{Name: "keys-wireguard-relay-cluster-infra", Namespace: constants.VPNNamespace}, secret))
   186  
   187  			assert.NotEqual(t, oldExpiry, secret.Annotations[wireguard.SecretExpires])
   188  			assert.NotEqual(t, oldPublicKey, string(secret.Data[wireguard.SecretPublicKey]))
   189  			assert.NotEqual(t, oldPrivateKey, string(secret.Data[wireguard.SecretPrivateKey]))
   190  			assert.Equal(t, oldIPAddress, string(secret.Data[wireguard.SecretIPAddress]))
   191  			return ctx
   192  		}).
   193  		Test("get the current instance", func(ctx f2.Context, t *testing.T) f2.Context {
   194  			instance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   195  			assert.NoError(t, err)
   196  			assert.NotNil(t, instance)
   197  
   198  			sameInstance, err := wireguard.GetInstance(ctx, k.Client, constants.RelayName, "cluster-infra", nil)
   199  			assert.NoError(t, err)
   200  			assert.NotNil(t, instance)
   201  			assert.Equal(t, instance, sameInstance)
   202  			return ctx
   203  		}).
   204  		Teardown("delete instance K8s secret", func(ctx f2.Context, t *testing.T) f2.Context {
   205  			require.NoError(t, k.Client.Delete(ctx, secret), "failed to cleanup instance secret")
   206  			return ctx
   207  		}).Feature()
   208  	f.Test(t, feature)
   209  }
   210  

View as plain text