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
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