Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Rework truncate function
Browse files Browse the repository at this point in the history
* now works for n < 32
* remove accidentially commited benchmark test
  • Loading branch information
Mario Manno committed Mar 31, 2020
1 parent 1c23539 commit 1dccbbd
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 192 deletions.
133 changes: 0 additions & 133 deletions pkg/names/bench_test.go

This file was deleted.

43 changes: 30 additions & 13 deletions pkg/names/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ const (

var allowedDNSLabelChars = regexp.MustCompile("[^-a-z0-9]*")

// DNSLabelSafe returns a string which is safe to use as a DNS label
// DNSLabelSafe filters invalid characters and returns a string that is safe to use as a DNS label.
// It does not enforce the required string length, see `Sanitize`.
//
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names
func DNSLabelSafe(name string) string {
name = strings.Replace(name, "_", "-", -1)
name = strings.ToLower(name)
name = allowedDNSLabelChars.ReplaceAllLiteralString(name, "")
name = strings.TrimPrefix(name, "-")
name = strings.TrimSuffix(name, "-")
name = strings.TrimLeft(name, "-")
name = strings.TrimRight(name, "-")
return name
}

Expand Down Expand Up @@ -141,15 +142,31 @@ func truncate(name string, max int) string {
return name
}

// TruncateMD5 truncates the string after n chars and add a hex encoded md5
// sum, to produce a uniq representation of the original string. Example:
// names are limited to 63 characters so we recalculate the name as <name
// trimmed to 31 characters>-<md5 hash of name>
func TruncateMD5(s string, n int) string {
if len(s) > n {
sumHex := md5.Sum([]byte(s))
sum := hex.EncodeToString(sumHex[:])
s = s[:n-32] + sum
// TruncateMD5 truncates the string to n chars and adds a hex encoded md5
// sum. Producing a uniq representation of the original string, if maxLen >= 32.
// Example: names are limited to 63 characters so we recalculate the name as
// <name trimmed to 30 characters>-<md5 hash of name>
func TruncateMD5(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}

sumHex := md5.Sum([]byte(s))
sum := hex.EncodeToString(sumHex[:]) // 32 chars

suffix := "-" + sum
suffixLen := 33

// enough space for suffix?
if maxLen < suffixLen {
return sum[:maxLen]
}
return s
if maxLen == suffixLen {
return sum
}

// s > maxLen now
// maxLen > 33 now
last := maxLen - suffixLen
return s[:last] + suffix
}
142 changes: 96 additions & 46 deletions pkg/names/names_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,33 @@ package names_test
import (
"fmt"

"code.cloudfoundry.org/quarks-utils/pkg/names"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"code.cloudfoundry.org/quarks-utils/pkg/names"
)

var _ = Describe("Names", func() {
type test struct {
arg1 string
arg string
result string
n int
}
long31 := "a123456789012345678901234567890"
long63 := long31 + "b123456789012345678901234567890c"
long253 := long63 + long63 + long63 + long63 + "d"
str31 := "a123456789012345678901234567890"
str32 := `123456789012345678901234567890AA`
str63 := str31 + "b123456789012345678901234567890c"
str253 := str63 + str63 + str63 + str63 + "d"

Context("JobName", func() {
tests := []test{
{arg1: "ab1", result: "ab1", n: 20},
{arg1: "a-b1", result: "a-b1-", n: 21},
{arg1: long31, result: "a123456789012345678901234567890-", n: 48},
{arg1: long63, result: long63[:39] + "-", n: 56},
{arg: "ab1", result: "ab1", n: 20},
{arg: "a-b1", result: "a-b1-", n: 21},
{arg: str31, result: "a123456789012345678901234567890-", n: 48},
{arg: str63, result: str63[:39] + "-", n: 56},
}

It("produces valid k8s job names", func() {
for _, t := range tests {
r, err := names.JobName(t.arg1)
r, err := names.JobName(t.arg)
Expect(err).ToNot(HaveOccurred())
Expect(r).To(ContainSubstring(t.result), fmt.Sprintf("%#v", t))
Expect(r).To(HaveLen(t.n), fmt.Sprintf("%#v", t))
Expand All @@ -40,68 +40,118 @@ var _ = Describe("Names", func() {
Context("Sanitize", func() {
// according to docs/naming.md
tests := []test{
{arg1: "AB1", result: "ab1"},
{arg1: "ab1", result: "ab1"},
{arg1: "1bc", result: "1bc"},
{arg1: "a-b", result: "a-b"},
{arg1: "a_b", result: "a-b"},
{arg1: "a_b_123", result: "a-b-123"},
{arg1: "-abc", result: "abc"},
{arg1: "abc-", result: "abc"},
{arg1: "_abc_", result: "abc"},
{arg1: "-abc-", result: "abc"},
{arg1: "abcü.123:4", result: "abc1234"},
{arg1: long63, result: long63},
{arg1: long63 + "0", result: long31 + "f61acdbce0e8ea6e4912f53bde4de866"},
{arg: "AB1", result: "ab1"},
{arg: "ab1", result: "ab1"},
{arg: "1bc", result: "1bc"},
{arg: "a-b", result: "a-b"},
{arg: "a_b", result: "a-b"},
{arg: "a_b_123", result: "a-b-123"},
{arg: "-abc", result: "abc"},
{arg: "abc-", result: "abc"},
{arg: "_abc_", result: "abc"},
{arg: "-abc-", result: "abc"},
{arg: "abcü.123:4", result: "abc1234"},
{arg: str63, result: str63},
{arg: str63 + "0", result: str31[:30] + "-f61acdbce0e8ea6e4912f53bde4de866"},
}

It("produces valid k8s names", func() {
for _, t := range tests {
Expect(names.Sanitize(t.arg1)).To(Equal(t.result), fmt.Sprintf("%#v", t))
Expect(names.Sanitize(t.arg)).To(Equal(t.result), fmt.Sprintf("%#v", t))
}
})
})

Context("SanitizeSubdomain", func() {
tests := []test{
{arg1: "AB1", result: "ab1"},
{arg1: "ab1", result: "ab1"},
{arg1: "1bc", result: "1bc"},
{arg1: "a-b", result: "a-b"},
{arg1: "a_b", result: "a-b"},
{arg1: "a_b_123", result: "a-b-123"},
{arg1: "-abc", result: "abc"},
{arg1: "abc-", result: "abc"},
{arg1: "_abc_", result: "abc"},
{arg1: "-abc-", result: "abc"},
{arg1: ".a.b.c.", result: "a.b.c"},
{arg1: "abcü.123:4", result: "abc.1234"},
{arg1: long253, result: long253},
{arg: "AB1", result: "ab1"},
{arg: "ab1", result: "ab1"},
{arg: "1bc", result: "1bc"},
{arg: "a-b", result: "a-b"},
{arg: "a_b", result: "a-b"},
{arg: "a_b_123", result: "a-b-123"},
{arg: "-abc", result: "abc"},
{arg: "abc-", result: "abc"},
{arg: "_abc_", result: "abc"},
{arg: "-abc-", result: "abc"},
{arg: ".a.b.c.", result: "a.b.c"},
{arg: "abcü.123:4", result: "abc.1234"},
{arg: str253, result: str253},
}

It("produces valid k8s names", func() {
for _, t := range tests {
Expect(names.SanitizeSubdomain(t.arg1)).To(Equal(t.result), fmt.Sprintf("%#v", t))
Expect(names.SanitizeSubdomain(t.arg)).To(Equal(t.result), fmt.Sprintf("%#v", t))
}
})

It("shortens long names", func() {
Expect(names.SanitizeSubdomain(long253 + "1")).To(HaveLen(253))
Expect(names.SanitizeSubdomain(str253 + "1")).To(HaveLen(253))
})
})

Context("VolumeName", func() {
tests := []test{
{arg1: "secret", result: "secret"},
{arg1: "secret.name", result: "name"},
{arg1: long63, result: long63},
{arg1: long63 + ".foo", result: "foo"},
{arg1: "foo." + long63, result: "a123456789012345678901234567890b123456789012345678901234567890c"},
{arg: "secret", result: "secret"},
{arg: "secret.name", result: "name"},
{arg: str63, result: str63},
{arg: str63 + ".foo", result: "foo"},
{arg: "foo." + str63, result: "a123456789012345678901234567890b123456789012345678901234567890c"},
}

It("produces valid k8s names", func() {
for _, t := range tests {
Expect(names.VolumeName(t.arg1)).To(Equal(t.result), fmt.Sprintf("%#v", t))
Expect(names.VolumeName(t.arg)).To(Equal(t.result), fmt.Sprintf("%#v", t))
}
})
})

Context("DNSLabelSafe", func() {
tests := []test{
{arg: "-Name", result: "name"},
{arg: "--_Name--", result: "name"},
{arg: "nA!müe123", result: "name123"},
}

It("produces valid k8s DNS labels chars", func() {
for _, t := range tests {
r := names.DNSLabelSafe(t.arg)
Expect(r).To(Equal(t.result), fmt.Sprintf("%#v", t))
}
})
})

Context("TruncateMD5", func() {
const (
longstringMD5 = `d3b442d33a939d736f8d44a1fbefa679`
)

tests := []test{
{arg: "longstring", n: 3, result: longstringMD5[:3]},
{arg: "longstring", n: 10, result: "longstring"},
{arg: "longstring", n: 11, result: "longstring"},
{
arg: "longstring" + str32, n: 32,
result: "4fa56ac8cd8f1badfb3226365b0771e8",
},
{
arg: "longstring" + str32, n: 33,
result: "4fa56ac8cd8f1badfb3226365b0771e8",
},
{
arg: "longstringAA" + str32, n: 43,
result: "longstring-07b4553eabfa74c177f570f0b87ce33e",
},
{
arg: "longstring" + str32 + str32, n: 63,
result: "longstring12345678901234567890-e42ccf2f5a0b4aca30676ffa42b15d16",
},
}

It("produces valid k8s DNS labels chars", func() {
for _, t := range tests {
r := names.TruncateMD5(t.arg, t.n)
Expect(r).To(Equal(t.result), fmt.Sprintf("%#v", t))
}
})
})
Expand Down

0 comments on commit 1dccbbd

Please sign in to comment.