mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
cmd/k8s-operator: fix base truncating for extra long Service names (#10825)
cmd/k8s-operator: fix base truncating for extra long Service names StatefulSet names for ingress/egress proxies are calculated using Kubernetes name generator and the parent resource name as a base. The name generator also cuts the base, but has a higher max cap. This commit fixes a bug where, if we get a shortened base back from the generator, we cut off too little as the base that we have cut will be passed into the generator again, which will then itself cut less because the base is shorter- so we end up with a too long name again. Updates tailscale/tailscale#10807 Co-authored-by: Maisem Ali <maisem@tailscale.com> Signed-off-by: Irbe Krumina <irbekrm@gmail.com>
This commit is contained in:
parent
331a6d105f
commit
469af614b0
@ -214,18 +214,19 @@ func (a *tailscaleSTSReconciler) Cleanup(ctx context.Context, logger *zap.Sugare
|
||||
// generation will NOT result in a StatefulSet name longer than 52 chars.
|
||||
// This is done because of https://github.com/kubernetes/kubernetes/issues/64023.
|
||||
func statefulSetNameBase(parent string) string {
|
||||
|
||||
base := fmt.Sprintf("ts-%s-", parent)
|
||||
|
||||
// Calculate what length name GenerateName returns for this base.
|
||||
generator := names.SimpleNameGenerator
|
||||
generatedName := generator.GenerateName(base)
|
||||
|
||||
if excess := len(generatedName) - maxStatefulSetNameLength; excess > 0 {
|
||||
base = base[:len(base)-excess-1] // take extra char off to make space for hyphen
|
||||
base = base + "-" // re-instate hyphen
|
||||
for {
|
||||
generatedName := generator.GenerateName(base)
|
||||
excess := len(generatedName) - maxStatefulSetNameLength
|
||||
if excess <= 0 {
|
||||
return base
|
||||
}
|
||||
base = base[:len(base)-1-excess] // cut off the excess chars
|
||||
if !strings.HasSuffix(base, "-") { // dash may have been cut by the generator
|
||||
base = base + "-"
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func (a *tailscaleSTSReconciler) reconcileHeadlessService(ctx context.Context, logger *zap.SugaredLogger, sts *tailscaleSTSConfig) (*corev1.Service, error) {
|
||||
|
@ -6,6 +6,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -19,32 +22,20 @@
|
||||
// https://github.com/kubernetes/kubernetes/blob/v1.28.4/staging/src/k8s.io/apiserver/pkg/storage/names/generate.go#L45.
|
||||
// https://github.com/kubernetes/kubernetes/pull/116430
|
||||
func Test_statefulSetNameBase(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
out string
|
||||
}{
|
||||
{
|
||||
name: "43 chars",
|
||||
in: "oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9xb",
|
||||
out: "ts-oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9xb-",
|
||||
},
|
||||
{
|
||||
name: "44 chars",
|
||||
in: "oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9xbo",
|
||||
out: "ts-oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9xb-",
|
||||
},
|
||||
{
|
||||
name: "42 chars",
|
||||
in: "oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9x",
|
||||
out: "ts-oidhexl9o832hcbhyg4uz6o0s7u9uae54h5k8ofs9x-",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := statefulSetNameBase(tt.in); got != tt.out {
|
||||
t.Errorf("stsNamePrefix(%s) = %q, want %s", tt.in, got, tt.out)
|
||||
}
|
||||
})
|
||||
// Service name lengths can be 1 - 63 chars, be paranoid and test them all.
|
||||
var b strings.Builder
|
||||
for b.Len() < 63 {
|
||||
if _, err := b.WriteString("a"); err != nil {
|
||||
t.Fatalf("error writing to string builder: %v", err)
|
||||
}
|
||||
baseLength := len(b.String())
|
||||
if baseLength > 43 {
|
||||
baseLength = 43 // currently 43 is the max base length
|
||||
}
|
||||
wantsNameR := regexp.MustCompile(`^ts-a{` + fmt.Sprint(baseLength) + `}-$`) // to match a string like ts-aaaa-
|
||||
gotName := statefulSetNameBase(b.String())
|
||||
if !wantsNameR.MatchString(gotName) {
|
||||
t.Fatalf("expected string %s to match regex %s ", gotName, wantsNameR.String()) // fatal rather than error as this test is called 63 times
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user