mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-10 10:03:43 +00:00
f1ccdcc713
This is the start of an integration/e2e test suite for the tailscale operator. It currently only tests two major features, ingress proxy and API server proxy, but we intend to expand it to cover more features over time. It also only supports manual runs for now. We intend to integrate it into CI checks in a separate update when we have planned how to securely provide CI with the secrets required for connecting to a test tailnet. Updates #12622 Change-Id: I31e464bb49719348b62a563790f2bc2ba165a11b Co-authored-by: Irbe Krumina <irbe@tailscale.com> Signed-off-by: Tom Proctor <tomhjp@users.noreply.github.com>
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
|
kube "tailscale.com/k8s-operator"
|
|
"tailscale.com/tstest"
|
|
)
|
|
|
|
// See [TestMain] for test requirements.
|
|
func TestIngress(t *testing.T) {
|
|
if tsClient == nil {
|
|
t.Skip("TestIngress requires credentials for a tailscale client")
|
|
}
|
|
|
|
ctx := context.Background()
|
|
cfg := config.GetConfigOrDie()
|
|
cl, err := client.New(cfg, client.Options{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Apply nginx
|
|
createAndCleanup(t, ctx, cl, &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "nginx",
|
|
Namespace: "default",
|
|
Labels: map[string]string{
|
|
"app.kubernetes.io/name": "nginx",
|
|
},
|
|
},
|
|
Spec: corev1.PodSpec{
|
|
Containers: []corev1.Container{
|
|
{
|
|
Name: "nginx",
|
|
Image: "nginx",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
// Apply service to expose it as ingress
|
|
svc := &corev1.Service{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test-ingress",
|
|
Namespace: "default",
|
|
Annotations: map[string]string{
|
|
"tailscale.com/expose": "true",
|
|
},
|
|
},
|
|
Spec: corev1.ServiceSpec{
|
|
Selector: map[string]string{
|
|
"app.kubernetes.io/name": "nginx",
|
|
},
|
|
Ports: []corev1.ServicePort{
|
|
{
|
|
Name: "http",
|
|
Protocol: "TCP",
|
|
Port: 80,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
createAndCleanup(t, ctx, cl, svc)
|
|
|
|
// TODO: instead of timing out only when test times out, cancel context after 60s or so.
|
|
if err := wait.PollUntilContextCancel(ctx, time.Millisecond*100, true, func(ctx context.Context) (done bool, err error) {
|
|
maybeReadySvc := &corev1.Service{ObjectMeta: objectMeta("default", "test-ingress")}
|
|
if err := get(ctx, cl, maybeReadySvc); err != nil {
|
|
return false, err
|
|
}
|
|
isReady := kube.SvcIsReady(maybeReadySvc)
|
|
if isReady {
|
|
t.Log("Service is ready")
|
|
}
|
|
return isReady, nil
|
|
}); err != nil {
|
|
t.Fatalf("error waiting for the Service to become Ready: %v", err)
|
|
}
|
|
|
|
var resp *http.Response
|
|
if err := tstest.WaitFor(time.Second*60, func() error {
|
|
// TODO(tomhjp): Get the tailnet DNS name from the associated secret instead.
|
|
// If we are not the first tailnet node with the requested name, we'll get
|
|
// a -N suffix.
|
|
resp, err = tsClient.HTTPClient.Get(fmt.Sprintf("http://%s-%s:80", svc.Namespace, svc.Name))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatalf("error trying to reach service: %v", err)
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("unexpected status: %v; response body s", resp.StatusCode)
|
|
}
|
|
}
|