cmd/k8s-operator: support being the default loadbalancer controller

Updates #502

Signed-off-by: Mike Beaumont <mjboamail@gmail.com>
pull/9083/head
Mike Beaumont 10 months ago committed by Maisem Ali
parent 4af22f3785
commit ce4bf41dcf

@ -183,6 +183,9 @@ waitOnline:
// startReconcilers starts the controller-runtime manager and registers the
// ServiceReconciler.
func startReconcilers(zlog *zap.SugaredLogger, tsNamespace string, restConfig *rest.Config, tsClient *tailscale.Client, image, priorityClassName, tags string) {
var (
isDefaultLoadBalancer = defaultBool("OPERATOR_DEFAULT_LOAD_BALANCER", false)
)
startlog := zlog.Named("startReconcilers")
// For secrets and statefulsets, we only get permission to touch the objects
// in the controller's own namespace. This cannot be expressed by
@ -234,9 +237,10 @@ func startReconcilers(zlog *zap.SugaredLogger, tsNamespace string, restConfig *r
Watches(&appsv1.StatefulSet{}, reconcileFilter).
Watches(&corev1.Secret{}, reconcileFilter).
Complete(&ServiceReconciler{
ssr: ssr,
Client: mgr.GetClient(),
logger: zlog.Named("service-reconciler"),
ssr: ssr,
Client: mgr.GetClient(),
logger: zlog.Named("service-reconciler"),
isDefaultLoadBalancer: isDefaultLoadBalancer,
})
if err != nil {
startlog.Fatalf("could not create controller: %v", err)

@ -650,6 +650,52 @@ func TestCustomPriorityClassName(t *testing.T) {
expectEqual(t, fc, expectedSTS(shortName, fullName, "custom-priority-class-name", "tailscale-critical"))
}
func TestDefaultLoadBalancer(t *testing.T) {
fc := fake.NewFakeClient()
ft := &fakeTSClient{}
zl, err := zap.NewDevelopment()
if err != nil {
t.Fatal(err)
}
sr := &ServiceReconciler{
Client: fc,
ssr: &tailscaleSTSReconciler{
Client: fc,
tsClient: ft,
defaultTags: []string{"tag:k8s"},
operatorNamespace: "operator-ns",
proxyImage: "tailscale/tailscale",
},
logger: zl.Sugar(),
isDefaultLoadBalancer: true,
}
// Create a service that we should manage, and check that the initial round
// of objects looks right.
mustCreate(t, fc, &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
// The apiserver is supposed to set the UID, but the fake client
// doesn't. So, set it explicitly because other code later depends
// on it being set.
UID: types.UID("1234-UID"),
},
Spec: corev1.ServiceSpec{
ClusterIP: "10.20.30.40",
Type: corev1.ServiceTypeLoadBalancer,
},
})
expectReconciled(t, sr, "default", "test")
fullName, shortName := findGenName(t, fc, "default", "test")
expectEqual(t, fc, expectedSecret(fullName))
expectEqual(t, fc, expectedHeadlessService(shortName))
expectEqual(t, fc, expectedSTS(shortName, fullName, "default-test", ""))
}
func expectedSecret(name string) *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{
@ -780,6 +826,9 @@ func findGenName(t *testing.T, client client.Client, ns, name string) (full, noS
if err != nil {
t.Fatalf("finding secret for %q: %v", name, err)
}
if s == nil {
t.Fatalf("no secret found for %q", name)
}
return s.GetName(), strings.TrimSuffix(s.GetName(), "-0")
}

@ -20,8 +20,9 @@ import (
type ServiceReconciler struct {
client.Client
ssr *tailscaleSTSReconciler
logger *zap.SugaredLogger
ssr *tailscaleSTSReconciler
logger *zap.SugaredLogger
isDefaultLoadBalancer bool
}
func childResourceLabels(name, ns, typ string) map[string]string {
@ -177,8 +178,8 @@ func (a *ServiceReconciler) shouldExpose(svc *corev1.Service) bool {
func (a *ServiceReconciler) hasLoadBalancerClass(svc *corev1.Service) bool {
return svc != nil &&
svc.Spec.Type == corev1.ServiceTypeLoadBalancer &&
svc.Spec.LoadBalancerClass != nil &&
*svc.Spec.LoadBalancerClass == "tailscale"
(svc.Spec.LoadBalancerClass != nil && *svc.Spec.LoadBalancerClass == "tailscale" ||
svc.Spec.LoadBalancerClass == nil && a.isDefaultLoadBalancer)
}
func (a *ServiceReconciler) hasAnnotation(svc *corev1.Service) bool {

Loading…
Cancel
Save